• Advertisement
Sign in to follow this  

shared pointer instead of CComPtr, How to release()?

This topic is 1659 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi

 

I want to create an array of vertex buffers using std::shared_ptr. How can set the deleter to the ::Release() member? I need this so I can InstBuffers.clear() before resetting the device.

for(int i=0;i<1024;i++){
		std::shared_ptr<LPDIRECT3DVERTEXBUFFER9> spNewBuffer(new LPDIRECT3DVERTEXBUFFER9/*, std::mem_fun_ref(IDirect3DVertexBuffer9::Release())*/);
		LPDIRECT3DVERTEXBUFFER9 pTempBuf = *spNewBuffer.get();

		hr = d3ddev->CreateVertexBuffer(BufferSize, D3DUSAGE_DYNAMIC, NULL, D3DPOOL_DEFAULT, &pTempBuf, NULL);

		if( hr!=D3D_OK ){
			MessageBox(NULL, L"Failed to make buffer", L"Error", MB_OK);
			return false;
		} else {
			InstBuffers.push_back(spNewBuffer);
		}
	}

Share this post


Link to post
Share on other sites
Advertisement

Pass a function that calls Release as the second argument to the shared pointer.

std::shared_ptr<T> a(new T, [](T *ptr) {ptr->Release();});

Share this post


Link to post
Share on other sites

I get a red line ..[](LPDIRECT3DVERTEXBUFFER9 *ptr){ptr->Release();}...

std::shared_ptr<LPDIRECT3DVERTEXBUFFER9> spNewBuffer(new LPDIRECT3DVERTEXBUFFER9, [](LPDIRECT3DVERTEXBUFFER9 *ptr){ptr->Release();});
error C2227: left of '->Release' must point to class/struct/union/generic type
1>          type is 'LPDIRECT3DVERTEXBUFFER9 *'

Share this post


Link to post
Share on other sites

It's already a pointer... windows with its LP at the start of a name => it's already a pointer (EDIT: So a LPDIRECT3DVERTEXBUFFER9* is actually a DIRECT3DVERTEXBUFFER9**)

 

That means you don't want the shared pointer to be of type LPDIRECT3DVERTEXBUFFER9 either, it wants to be a DIRECT3DVERTEXBUFFER9.

Edited by Paradigm Shifter

Share this post


Link to post
Share on other sites

Seems like shared_ptr dont like COM interfaces

std::shared_ptr<IDirect3DVertexBuffer9> spNewBuffer(new IDirect3DVertexBuffer9, [](IDirect3DVertexBuffer9 *ptr){ptr->Release();} );

Gives errors:

error C2259: 'IDirect3DVertexBuffer9' : cannot instantiate abstract class
1>          due to following members:
1>          'HRESULT IDirect3DVertexBuffer9::QueryInterface(const IID &,void **)' : is abstract
1>          c:\program files (x86)\microsoft directx sdk (june 2010)\include\d3d9.h(1478) : see declaration of 'IDirect3DVertexBuffer9::QueryInterface'
1>          'ULONG IDirect3DVertexBuffer9::AddRef(void)' : is abstract
1>          c:\program files (x86)\microsoft directx sdk (june 2010)\include\d3d9.h(1479) : see declaration of 'IDirect3DVertexBuffer9::AddRef'
1>          'ULONG IDirect3DVertexBuffer9::Release(void)' : is abstract
1>          c:\program files (x86)\microsoft directx sdk (june 2010)\include\d3d9.h(1480) : see declaration of 'IDirect3DVertexBuffer9::Release'
1>          'HRESULT IDirect3DVertexBuffer9::GetDevice(IDirect3DDevice9 **)' : is abstract
1>          c:\program files (x86)\microsoft directx sdk (june 2010)\include\d3d9.h(1483) : see declaration of 'IDirect3DVertexBuffer9::GetDevice'
1>          'HRESULT IDirect3DVertexBuffer9::SetPrivateData(const GUID &,const void *,DWORD,DWORD)' : is abstract
1>          c:\program files (x86)\microsoft directx sdk (june 2010)\include\d3d9.h(1484) : see declaration of 'IDirect3DVertexBuffer9::SetPrivateData'
1>          'HRESULT IDirect3DVertexBuffer9::GetPrivateData(const GUID &,void *,DWORD *)' : is abstract
1>          c:\program files (x86)\microsoft directx sdk (june 2010)\include\d3d9.h(1485) : see declaration of 'IDirect3DVertexBuffer9::GetPrivateData'
1>          'HRESULT IDirect3DVertexBuffer9::FreePrivateData(const GUID &)' : is abstract
1>          c:\program files (x86)\microsoft directx sdk (june 2010)\include\d3d9.h(1486) : see declaration of 'IDirect3DVertexBuffer9::FreePrivateData'
1>          'DWORD IDirect3DVertexBuffer9::SetPriority(DWORD)' : is abstract
1>          c:\program files (x86)\microsoft directx sdk (june 2010)\include\d3d9.h(1487) : see declaration of 'IDirect3DVertexBuffer9::SetPriority'
1>          'DWORD IDirect3DVertexBuffer9::GetPriority(void)' : is abstract
1>          c:\program files (x86)\microsoft directx sdk (june 2010)\include\d3d9.h(1488) : see declaration of 'IDirect3DVertexBuffer9::GetPriority'
1>          'void IDirect3DVertexBuffer9::PreLoad(void)' : is abstract
1>          c:\program files (x86)\microsoft directx sdk (june 2010)\include\d3d9.h(1489) : see declaration of 'IDirect3DVertexBuffer9::PreLoad'
1>          'D3DRESOURCETYPE IDirect3DVertexBuffer9::GetType(void)' : is abstract
1>          c:\program files (x86)\microsoft directx sdk (june 2010)\include\d3d9.h(1490) : see declaration of 'IDirect3DVertexBuffer9::GetType'
1>          'HRESULT IDirect3DVertexBuffer9::Lock(UINT,UINT,void **,DWORD)' : is abstract
1>          c:\program files (x86)\microsoft directx sdk (june 2010)\include\d3d9.h(1491) : see declaration of 'IDirect3DVertexBuffer9::Lock'
1>          'HRESULT IDirect3DVertexBuffer9::Unlock(void)' : is abstract
1>          c:\program files (x86)\microsoft directx sdk (june 2010)\include\d3d9.h(1492) : see declaration of 'IDirect3DVertexBuffer9::Unlock'
1>          'HRESULT IDirect3DVertexBuffer9::GetDesc(D3DVERTEXBUFFER_DESC *)' : is abstract
1>          c:\program files (x86)\microsoft directx sdk (june 2010)\include\d3d9.h(1493) : see declaration of 'IDirect3DVertexBuffer9::GetDesc'

Share this post


Link to post
Share on other sites

That's because you can't create an IDirect3DVertexBuffer9 using new IDirect3DVertexBuffer9 (it's an abstract class).

 

How do you normally create an IDirect3DVertexBuffer9 derived object?

Edited by Paradigm Shifter

Share this post


Link to post
Share on other sites

This seems to compile:

std::shared_ptr<LPDIRECT3DVERTEXBUFFER9> spNewBuffer(new LPDIRECT3DVERTEXBUFFER9, [](LPDIRECT3DVERTEXBUFFER9 (*ptr)){(*ptr)->Release();} );
Edited by Tispe

Share this post


Link to post
Share on other sites

Then you are creating an object of type

 

IDirect3DVertexBuffer9**

 

which probably isn't what you want...

 

EDIT:

 

shared_pointer<T> sp(new T);

 

creates a shared pointer to a T. You are effectively doing this in the above post:

 

shared_pointer<T*> sp(new T*);

Edited by Paradigm Shifter

Share this post


Link to post
Share on other sites

Right, I get a runtime error when InstBuffers.clear();

 

Unhandled exception at 0x778815de in Game.exe: 0xC0000005: Access violation reading location 0xcdcdcdcd.

private:
	virtual void _Destroy()
		{	// destroy managed resource
		_Dtor(_Ptr);
		}

Should I just wrap everything in a class and release in the destructor, or do you have better ideas?

Share this post


Link to post
Share on other sites

I want to create a shared pointer to the vertex buffer or shared pointer to the pointer to the vertex buffer.

 

The creation and attaching the actual buffer to the last pointer on the chain is done further down in code

d3ddev->CreateVertexBuffer(BufferSize, D3DUSAGE_DYNAMIC, NULL, D3DPOOL_DEFAULT, &pTempBuf, NULL);

Share this post


Link to post
Share on other sites

Unless I'm missing something obvious, isn't it the pTempBuf in your case you want to store in the smart pointer?

IDirect3DVertexBuffer9 *pTempBuf;
 
d3ddev->CreateVertexBuffer(BufferSize, D3DUSAGE_DYNAMIC, NULL, D3DPOOL_DEFAULT, &pTempBuf, NULL);
 
std::smart_ptr<IDirect3DVertexBuffer9> spNewBuffer(pTempBuf, [](IDirect3DVertexBuffer9 *p) {p->Release();});

Something along those lines perhaps.

Share this post


Link to post
Share on other sites

Looking at the original question, what is wrong with using smart pointers designed to work with COM objects? You already have a reference counter in your COM object, why create another one?

 

The only case I can think of anything else really makes sense is stuff like std::unique_ptr, since then it is clear that the object owns the texture/vertex buffer/whatever and should be free to modify it (contents, replace with new object, etc.) how it likes without worrying about if something else kept a reference.

Edited by SyncViews

Share this post


Link to post
Share on other sites

Unless I'm missing something obvious, isn't it the pTempBuf in your case you want to store in the smart pointer?
IDirect3DVertexBuffer9 *pTempBuf;
 
d3ddev->CreateVertexBuffer(BufferSize, D3DUSAGE_DYNAMIC, NULL, D3DPOOL_DEFAULT, &pTempBuf, NULL);
 
std::smart_ptr spNewBuffer(pTempBuf, [](IDirect3DVertexBuffer9 *p) {p->Release();});
Something along those lines perhaps.

 

Thank you, works like a charm now.

for(int i=0;i<1024;i++){
		IDirect3DVertexBuffer9 *pTempBuf;
		hr = d3ddev->CreateVertexBuffer(BufferSize, D3DUSAGE_DYNAMIC, NULL, D3DPOOL_DEFAULT, &pTempBuf, NULL);

		if( hr!=D3D_OK ){
			MessageBox(NULL, L"Failed to make Buffer", L"Error", MB_OK);
			return false;
		} else {
			std::shared_ptr<IDirect3DVertexBuffer9> spNewBuffer(pTempBuf, [](IDirect3DVertexBuffer9 *p) {p->Release();});
			InstBuffers.push_back(spNewBuffer);
		}
	}
Edited by Tispe

Share this post


Link to post
Share on other sites

Ok, I have a new problem relating to std::shared_ptr.

 

I have an std::map which holds shared pointers to struct, which again hold shared pointers to other structs. Somehow down this chain some shared pointers won't get destroyed which won't trigger the Release(). Before I clear() the map the shared pointer to the vertex buffer has 2 strong refs, but after I clear() the map it still has 2 strong refs.

std::map<DWORD, std::shared_ptr<InstancedMesh> > InstancedMeshes;
struct InstancedMesh
{
	DWORD ID;
	std::vector<std::shared_ptr<InstancedMeshSubset> > MeshSubsets;
};
struct InstancedMeshSubset
{
	DWORD SubsetID;
	std::shared_ptr<Mesh> Mesh;
	std::vector<InstanceMember> Members;
	std::shared_ptr<IDirect3DVertexBuffer9> spInstBuffer;
};

As you can see it goes as follows: InstancedMeshes[ID]->MeshSubsets->spInstBuffer->Release().

I call InstancedMeshes.clear(); But Release() does not get called.

Share this post


Link to post
Share on other sites

Is MeshSubsets the only references to InstancedMeshSubset in existence? Is spInstBuffer the only reference to the IDirect3DVertexBuffer9 in existance? For a start if you dont know you could see if the destructor for InstancedMeshSubset gets called.

 

If there not then Release will not be called, and it is exactly what shared pointers are for (since otherwise the other reference  would be invalid and probably break something).

Share this post


Link to post
Share on other sites


Is MeshSubsets the only references to InstancedMeshSubset in existence?

 

Yes, only in this map is InstancedMeshSubset referenced.

 

The buffer it self is referenced in two places. Inside the map and in a vector array.

 

I want this vector array to act as a "pool" of available buffers to be used on a frame by frame basis. So that the map is cleared every frame. And if I need to reset the device I will clear the vector aswell.

 

But, even if I clear the map, the buffers still have 2 strong refs. They have two refs before map::clear() and two after... They should only have 1 ref after the map clear, from the vector array. But somehow in the chain InstancedMeshes[ID]->MeshSubsets->spInstBuffer->Release() the objects stops being destroyed and the vertex buffers remain referenced.

Edited by Tispe

Share this post


Link to post
Share on other sites

The buffer being "std::shared_ptr<IDirect3DVertexBuffer9> spInstBuffer;", and what map? If you have 2 shared pointers like that Release will not be called until you destroy both shared pointers. Add debug statements to the destructors of whatever owned the shared_ptr (eg. to "struct InstancedMeshSubset") so you can verify all the shared_ptr objects are destroyed.

 

Also how are you telling at present that Release is not called?

Edited by SyncViews

Share this post


Link to post
Share on other sites

My bad. The map::clear() do kill all objects in it. I found out I called RecoverDevice() before clearing the map somewhere else in the code. Thanks for input.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement