https://docs.microsoft.com/zh-cn/cpp/atl/reference/ccomptr-class?view=vs-2017
https://docs.microsoft.com/zh-cn/cpp/atl/reference/ccomptr-class?view=vs-2017
https://docs.microsoft.com/zh-cn/cpp/atl/reference/ccomptrbase-class?view=vs-2017
CComPtrBase 类 为使用基于COM 的内存例程的智能指针类提供了基础。
/
// COM Smart pointers
template <class T>
class _NoAddRefReleaseOnCComPtr :
public T
{
private:
STDMETHOD_(ULONG, AddRef)()=0;
STDMETHOD_(ULONG, Release)()=0;
};
//CComPtrBase provides the basis for all other smart pointers
//The other smartpointers add their own constructors and operators
template <class T>
class CComPtrBase
{
protected:
CComPtrBase() throw()
{
p = NULL;
}
CComPtrBase(_Inout_opt_ T* lp) throw()
{
p = lp;
// 普通的引用规则,当接口指针赋值进行赋值操作,应该AddRef
// 确保了通过这个指针指针进行的接口操作时接口没有销毁
if (p != NULL)
p->AddRef();
}
void Swap(CComPtrBase& other)
{
T* pTemp = p;
p = other.p;
other.p = pTemp;
}
public:
typedef T _PtrClass;
~CComPtrBase() throw()
{
// 同样的,当智能指针销毁,应该减少引用计数
// 值观的一个用途就是,局部变量的智能指针,通过构造和析构函数来管理引用计数
if (p)
p->Release();
}
operator T*() const throw()
{
return p;
}
T& operator*() const
{
ATLENSURE(p!=NULL);
return *p;
}
//The assert on operator& usually indicates a bug. If this is really
//what is needed, however, take the address of the p member explicitly.
T** operator&() throw()
{
ATLASSERT(p==NULL);
return &p;
}
_NoAddRefReleaseOnCComPtr<T>* operator->() const throw()
{
ATLASSERT(p!=NULL);
return (_NoAddRefReleaseOnCComPtr<T>*)p;
}
bool operator!() const throw()
{
return (p == NULL);
}
bool operator<(_In_opt_ T* pT) const throw()
{
return p < pT;
}
bool operator!=(_In_opt_ T* pT) const
{
return !operator==(pT);
}
bool operator==(_In_opt_ T* pT) const throw()
{
return p == pT;
}
// Release the interface and set to NULL
// 显式的释放这个指针
void Release() throw()
{
T* pTemp = p;
if (pTemp)
{
p = NULL;
pTemp->Release();
}
}
// Compare two objects for equivalence
inline bool IsEqualObject(_Inout_opt_ IUnknown* pOther) throw();
// Attach to an existing interface (does not AddRef)
// 这里需要注意,Attach 到一个已经存在的接口,不需要调用AddRef
// 但是,会将之前绑定的接口,进行Release 操作
// 这就要求我们,当重复、连续Attach 到同一个接口,将导致,该接口的引用计数异常
// 这个问题本身就是一个,引用计数的问题,因为,Attach 和 Detach 要对应才保证程序的正常执行
void Attach(_In_opt_ T* p2) throw()
{
if (p)
{
ULONG ref = p->Release();
(ref);
// Attaching to the same object only works if duplicate references are being coalesced. Otherwise
// re-attaching will cause the pointer to be released and may cause a crash on a subsequent dereference.
ATLASSERT(ref != 0 || p2 != p);
}
p = p2;
}
// Detach the interface (does not Release)
// 和上面的Attach 对应
T* Detach() throw()
{
T* pt = p;
p = NULL;
return pt;
}
// 将当前的接口copy 到另外的指针,理所应当的会需要我们增加当前接口指针的引用计数
_Check_return_ HRESULT CopyTo(_COM_Outptr_result_maybenull_ T** ppT) throw()
{
ATLASSERT(ppT != NULL);
if (ppT == NULL)
return E_POINTER;
*ppT = p;
if (p)
p->AddRef();
return S_OK;
}
_Check_return_ HRESULT SetSite(_Inout_opt_ IUnknown* punkParent) throw()
{
return AtlSetChildSite(p, punkParent);
}
_Check_return_ HRESULT Advise(
_Inout_ IUnknown* pUnk,
_In_ const IID& iid,
_Out_ LPDWORD pdw) throw()
{
return AtlAdvise(p, pUnk, iid, pdw);
}
_Check_return_ HRESULT CoCreateInstance(
_In_ REFCLSID rclsid,
_Inout_opt_ LPUNKNOWN pUnkOuter = NULL,
_In_ DWORD dwClsContext = CLSCTX_ALL) throw()
{
ATLASSERT(p == NULL);
return ::CoCreateInstance(rclsid, pUnkOuter, dwClsContext, __uuidof(T), (void**)&p);
}
#ifdef _ATL_USE_WINAPI_FAMILY_DESKTOP_APP
_Check_return_ HRESULT CoCreateInstance(
_In_z_ LPCOLESTR szProgID,
_Inout_opt_ LPUNKNOWN pUnkOuter = NULL,
_In_ DWORD dwClsContext = CLSCTX_ALL) throw()
{
CLSID clsid;
HRESULT hr = CLSIDFromProgID(szProgID, &clsid);
ATLASSERT(p == NULL);
if (SUCCEEDED(hr))
hr = ::CoCreateInstance(clsid, pUnkOuter, dwClsContext, __uuidof(T), (void**)&p);
return hr;
}
#endif // _ATL_USE_WINAPI_FAMILY_DESKTOP_APP
template <class Q>
_Check_return_ HRESULT QueryInterface(_Outptr_ Q** pp) const throw()
{
ATLASSERT(pp != NULL);
return p->QueryInterface(__uuidof(Q), (void**)pp);
}
T* p;
};
需要注意的一点:智能指针已经帮助我们进行了引用计数的操作,此时,我们不应该显式的调用Addref 和 Release 函数。