COM Smart Pointers

Started by
7 comments, last by Muhammad Haggag 16 years, 8 months ago
Are there any good COM smart pointer implementations. I am using C++, and VS8 Express. I am trying to use CComPtr in <Atlbase.h> to no avail. These are the compiler errors.

C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\atlmfc\include\atlcomcli.h(300) : error C2299: 'ATL::CComPtr<T>::operator =' : behavior change: an explicit specialization cannot be a copy constructor or copy assignment operator
        C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\atlmfc\include\atlcomcli.h(304) : see reference to class template instantiation 'ATL::CComPtr<T>' being compiled
C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\atlmfc\include\atlcomcli.h(300) : error C2299: 'ATL::CComPtr<T>::operator =' : behavior change: an explicit specialization cannot be a copy constructor or copy assignment operator
        with
        [
            T=IUnknown
        ]
        C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\atlmfc\include\atlcomcli.h(508) : see reference to class template instantiation 'ATL::CComPtr<T>' being compiled
        with
        [
            T=IUnknown
        ]
C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\atlmfc\include\atlcomcli.h(300) : error C2299: 'ATL::CComPtr<T>::operator =' : behavior change: an explicit specialization cannot be a copy constructor or copy assignment operator
        with
        [
            T=IPersistStream
        ]
        C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\atlmfc\include\atlcomcli.h(2215) : see reference to class template instantiation 'ATL::CComPtr<T>' being compiled
        with
        [
            T=IPersistStream
        ]
C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\atlmfc\include\atlbase.h(861) : error C2299: 'ATL::CAutoPtr<T>::CAutoPtr' : behavior change: an explicit specialization cannot be a copy constructor or copy assignment operator
        C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\atlmfc\include\atlbase.h(927) : see reference to class template instantiation 'ATL::CAutoPtr<T>' being compiled
C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\atlmfc\include\atlbase.h(884) : error C2299: 'ATL::CAutoPtr<T>::operator =' : behavior change: an explicit specialization cannot be a copy constructor or copy assignment operator
C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\atlmfc\include\atlbase.h(4522) : error C3203: 'CComAutoThreadModule' : unspecialized class template can't be used as a template argument for template parameter 'T', expected a real type
        C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\atlmfc\include\atlbase.h(4534) : see reference to class template instantiation 'ATL::CComAutoThreadModule<ThreadAllocator,dwWait>' being compiled
C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\atlmfc\include\atlcomcli.h(300) : error C2299: 'ATL::CComPtr<T>::operator =' : behavior change: an explicit specialization cannot be a copy constructor or copy assignment operator
        with
        [
            T=ITypeLib
        ]
        C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\atlmfc\include\atlbase.h(5982) : see reference to class template instantiation 'ATL::CComPtr<T>' being compiled
        with
        [
            T=ITypeLib
        ]
C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\atlmfc\include\atlcomcli.h(300) : error C2299: 'ATL::CComPtr<T>::operator =' : behavior change: an explicit specialization cannot be a copy constructor or copy assignment operator
        with
        [
            T=ICatRegister
        ]
        C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\atlmfc\include\atlbase.h(6100) : see reference to class template instantiation 'ATL::CComPtr<T>' being compiled
        with
        [
            T=ICatRegister
        ]
C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\atlmfc\include\atlcomcli.h(300) : error C2299: 'ATL::CComPtr<T>::operator =' : behavior change: an explicit specialization cannot be a copy constructor or copy assignment operator
        with
        [
            T=LPD3DXMESH
        ]
        c:\documents and settings\running\my documents\visual studio projects\yardville\source\../include/Renderdata.h(17) : see reference to class template instantiation 'ATL::CComPtr<T>' being compiled
        with
        [
            T=LPD3DXMESH
        ]



any ideas??!?? Not me... ------------------------------------------------------ So I started working on my own, but I would rather work with something more tested. Also, I am running into issues with the implementation; I cannot AddRef () to a COM object that I haven't yet acquired. So do I add an Acquire() method that will set a flag, such that while this flag is set, I need to call AddRef() next time I access the COM object before I reset the flag, however if the Com_ptr is destroyed before the item is released I will not call Release()?
template<class T>
class com_ptr
{
public:
	com_ptr(T* raw):ptr(raw),bRefNeeded(false)
	{
		if (ptr)
			ptr->AddRef();
	}

	com_ptr(const com_ptr<T> &rhs):ptr(rhs.ptr)
	{
		if (ptr)
			ptr->AddRef;
	}

	com_ptr& operator=(const com_ptr& rhs)
	{
		if ( this->ptr == rhs.ptr)
			return *this;

		if (ptr)
			ptr->Release();

		ptr = rhs.ptr; 
                if (ptr)
                        ptr->AddRef();
	}

   ~com_ptr()
   {
	   if (ptr && !bRefNeeded)
		   ptr->Release();
   }

   T* Acquire()
   {
           bRefNeeded = true; // or something of the sort !!!!!
	   return ptr;
   }

   T* Get()
   {
           if (ptr && bRefNeeded)
           {
                 ptr->AddRef();
                 bRefNeeded = false;
           } 

	   return ptr;
   }

   T& operator*() const
   {
      if (ptr && bRefNeeded)
           {
                 ptr->AddRef();
                 bRefNeeded = false;
           } 

      return *ptr;
   }

   T* operator->() const
   {
      if (ptr && bRefNeeded)
           {
                 ptr->AddRef();
                 bRefNeeded = false;
           } 
      return ptr;
   }
private:
   T* ptr;
   bool bRefNeeded;
};



[Edited by - DeafManNoEars on August 13, 2007 9:24:13 PM]
Advertisement
You can use Boost smart pointers with a custom deleter to hold a reference to a COM object. See the programming techniques page for more info.
Quote:Original post by Sneftel
You can use Boost smart pointers with a custom deleter to hold a reference to a COM object. See the programming techniques page for more info.


I'll look into that, thanks.


Doesn't this kind of kill me if a copy goes out of scope???
Quote:
All pw copies will share a single reference.


Or do you just call make_shared_from_COM for each copy.
Quote:Original post by DeafManNoEars
Doesn't this kind of kill me if a copy goes out of scope???


No, it doesn't (as long as you have other copies of the shared_ptr around). That quote refers to the fact that you are no longer using the internal reference count of the COM objects, but rather the shared_ptr's reference count.

Speaking of which, you might also be interested in using boost::intrusive_ptr with your COM pointers (since that will use the COM reference count):

void intrusive_ptr_add_ref( IUnknown const * const p ) {  p.AddRef();}void intrusive_ptr_release( IUnknown const * const p ) {  p.Release();}// ...typedef boost::intrusive_ptr< ID3DXMesh > MeshPtr;MeshPtr mesh;{  LPD3DXMESH meshptr = 0;  D3DXCreateMesh( ... );  MeshPtr( meshptr, false ).swap( mesh );}



jfl.
Quote:Original post by jflanglois
Quote:Original post by DeafManNoEars
Doesn't this kind of kill me if a copy goes out of scope???


No, it doesn't (as long as you have other copies of the shared_ptr around). That quote refers to the fact that you are no longer using the internal reference count of the COM objects, but rather the shared_ptr's reference count.




OK checked it out and it works perfectly. Thanks for clearing that up.
I used CComPtr a lot a while back and I didn't have any trouble. Post the code generating those errors.
John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!
You seem to be using CComPtr with an LPD3DXMESH, which is incorrect-the template parameter should be an interface, not an interface pointer. Instead of CComPtr<LPD3DXMESH>, use CComPtr<ID3DXMesh>. If you get more errors, post the code and the errors.

Quote:Original post by JohnBolton
I used CComPtr a lot a while back and I didn't have any trouble. Post the code generating those errors.


I can't even get this to compile, with errors pointing me to atlcomcli.h.

//file RenderData.h#include <atlbase.h>struct ID3DXMesh;class RenderData{public:	RenderData():m_pMesh(){};	~RenderData(){};private:	CComPtr<ID3DXMesh>		m_pMesh;};


I broke the above out of my project to make sure there wasn't something wrong with the way I was using it or another part of my app. i just try to instantiate a RenderData object on the stack and that's it (like below). It won't compile.

//Test.h#include "stdafx.h" // "renderdata.h" and <d3dx9.h> in hereint _tmain(int argc, _TCHAR* argv[]){        	return 0;}


This is my build log.
Compiling...stdafx.cpp  atlmfc\include\atlcomcli.h(300) : error C2299: 'ATL::CComPtr<T>::operator =' : behavior change: an explicit specialization cannot be a copy constructor or copy assignment operator  atlmfc\include\atlcomcli.h(304) : see reference to class template instantiation 'ATL::CComPtr<T>' being compiled  atlmfc\include\atlcomcli.h(300) : error C2299: 'ATL::CComPtr<T>::operator =' : behavior change: an explicit specialization cannot be a copy constructor or copy assignment operator        with        [            T=IUnknown        ]  atlmfc\include\atlcomcli.h(508) : see reference to class template instantiation 'ATL::CComPtr<T>' being compiled        with        [            T=IUnknown        ]  atlmfc\include\atlcomcli.h(300) : error C2299: 'ATL::CComPtr<T>::operator =' : behavior change: an explicit specialization cannot be a copy constructor or copy assignment operator        with        [            T=IPersistStream        ]  atlmfc\include\atlcomcli.h(2215) : see reference to class template instantiation 'ATL::CComPtr<T>' being compiled        with        [            T=IPersistStream        ]  atlmfc\include\atlbase.h(861) : error C2299: 'ATL::CAutoPtr<T>::CAutoPtr' : behavior change: an explicit specialization cannot be a copy constructor or copy assignment operator  atlmfc\include\atlbase.h(927) : see reference to class template instantiation 'ATL::CAutoPtr<T>' being compiled  atlmfc\include\atlbase.h(884) : error C2299: 'ATL::CAutoPtr<T>::operator =' : behavior change: an explicit specialization cannot be a copy constructor or copy assignment operator  atlmfc\include\atlbase.h(4522) : error C3203: 'CComAutoThreadModule' : unspecialized class template can't be used as a template argument for template parameter 'T', expected a real type  atlmfc\include\atlbase.h(4534) : see reference to class template instantiation 'ATL::CComAutoThreadModule<ThreadAllocator,dwWait>' being compiled  atlmfc\include\atlcomcli.h(300) : error C2299: 'ATL::CComPtr<T>::operator =' : behavior change: an explicit specialization cannot be a copy constructor or copy assignment operator        with        [            T=ITypeLib        ]    atlmfc\include\atlbase.h(5982) : see reference to class template instantiation 'ATL::CComPtr<T>' being compiled        with        [            T=ITypeLib        ]    atlmfc\include\atlcomcli.h(300) : error C2299: 'ATL::CComPtr<T>::operator =' : behavior change: an explicit specialization cannot be a copy constructor or copy assignment operator        with        [            T=ICatRegister        ]    atlmfc\include\atlbase.h(6100) : see reference to class template instantiation 'ATL::CComPtr<T>' being compiled        with        [            T=ICatRegister        ]          atlmfc\include\atlcomcli.h(300) : error C2299: 'ATL::CComPtr<T>::operator =' : behavior change: an explicit specialization cannot be a copy constructor or copy assignment operator        with        [            T=ID3DXMesh        ]


So, an explicit specialization cannot be a copy constructor or copy assignment operator. OK, how do I get around this?

This is not critical as
boost::shared_ptr
appears to do the trick.
The problem is that you're using the ATL provided with VC++ 7.1 with the VC++ 8 compiler. You're encountering one of the 'breaking changes' in the 8 compiler, described here. Other breaking changes are described here.

So, just use boost [smile].

This topic is closed to new replies.

Advertisement