1.导致内存泄露的一种调用方式:
下面方法是错误的:
IA *pA=NULL;
p->QueryInterfaces(...,&pA);//从某个已有接口查询获取IA
CComPtr<IA> spA(pA)
QueryInterface方法会导致pA->AddRef被调用一次,CComPtr<IA>构造函数又会调用一次AddRef,而最后spA析构时只调用了一次Release,因此COM对象没有被销毁,内存泄露了。
正确做法如下:
IA *pA=NULL;
p->QueryInterfaces(...,&pA);
CComPtr<IA> spA;
spA.Attach(pA);
或者
CComPtr<IA> spA(pA)
p->QueryInterfaces(...,&pA.p);
omPtr内部对引用类型产生Assert原因
不能使用的operator&
//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;
}
当你的CComPtr的p成员变量(集成而来的)不为NULL时,debug模式下会弹出错误对话框。看看上面的注释,这个函数被设计用来防止对智能指针直接调用取地址操作符的。实在要用,请用这种方法:&sp.p。
omPtr内部operator*
operator*
T& operator*() const
{
ATLENSURE(p!=NULL);
return *p;
}
有了这个操作,我们就可以使得CComPtr拥有和普通指针同样的行为,通过*p来获得p所指对象的引用。
omPtr内部operator T*
operator T*
operator T*() const throw()
{
return p;
}
这是个类型转换操作。调用方法如下:
CComPtr<IUnknown> sp=...
IUnknown* p=(IUnknown*)sp;
omPtr内部CopyTo
CopyTo
_Check_return_ HRESULT CopyTo(_Deref_out_opt_ T** ppT) throw()
{
ATLASSERT(ppT != NULL);
if (ppT == NULL)
return E_POINTER;
*ppT = p;
if (p)
p->AddRef();
return S_OK;
}
将自己的接口拷贝个参数指针,并调用AddRef。
omPtr内部Attach和Detach方法
void Attach(_In_opt_ T* p2) throw()
{
if (p)
p->Release();
p = p2;
}
// Detach the interface (does not Release)
T* Detach() throw()
{
T* pt = p;
p = NULL;
return pt;
}
Attach方法先释放原先p所指接口,然后接受新接口,注意,不会导致AddRef调用。
Detach方法将p设置为NULLL,然后返回接口。如果外部调用需要保存返回的接口,否则就遗失了。