ATL中包含的智能指针包括:CAutoPtr、CAutoPtrArray和CAutoPtrList, CComPtr和CComQIPtr
一、CAutoPtr、CAutoPtrArray和CAutoPtrList
CAutoPtr是普通智能指针类,CAutoPtrArray是智能指针数组,两者都在atlbase.h中声明;CAutoPtrList是智能指针列表,在atlcoll.h中声明。
二、CComPtr和CComQIPtr
CComPtr和CComQIPtr都是用来管理COM接口指针的类,CComQIPtr可完全取代CComPtr,两者的区别在于:CComQIPtr实现了运算符的重载功能,它可以自动调用QueryInterface()函数,CComQIPtr 唯一的缺点是不能定义 IUnknown * 指针。CComQIPtr<IUnknown > spUn是错误的。
1.声明和定义:
声明和定义一个CComQIPtr指针ISample。
CComQIPtr<ISample> spSample(IOtherInterface); 等价于
CComQIPtr<ISample> spSample =IOtherInterface;/*运算符重载*/ 等价于
CComQIPtr<ISample> spSample;
IOtherInterface->QueryInterface(IID_ISample, &spSample);
2.函数调用:
智能指针调用函数分智能指针函数调用和智能指针内部接口指针函数调用,如上面声明的spSample,
spSample.CoCreateInstance(),spSample.QueryInterface等价于API函数调用::CoCreateInstance()和::QueryInterface();
spSample.QueryInterface()等价于内部接口指针函数spSample->QueryInterface()。
spSample->AddRef()正确,但spSample->Release()是错误的,因为它调用的是内部接口函数,并不能完全释放智能指针,而后还会再调用一次Release()释放指针。
3.智能指针的使用
当对象的生命周期很长要小心使用;
当对象的生命周期不确定时不要使用;
千万不要使用全局的智能指针。
一个智能指针使用的问题:
MyFunc()
{
HRESULT hr;
CoInitialize(NULL);
{
CComPtr<ITestCOMPtr> spTestCOMPtr;
hr = spTestCOMPtr.CreateInstance(CLSID_TESTCOMPtr);
if(FAILED(hr))
{
returnl_hr;
}
//dosomethingof ITestCOMPtr
}
CoUninitialize();
}
如果没有红色括号标志智能指针的生命周期,spTestCOMPtr将在程序结束时,也就是CoUninitialize()结束之后才释放,这时套间已经结束,从而引起程序崩溃。
附: CComPtr 和 CComQIPtr类定义
template
class CComPtr {
public:
typedef T _PtrClass;
CComPtr() {p=NULL;}
CComPtr(T* lp) {
if ((p = lp) != NULL)
p->AddRef();
}
CComPtr(const CComPtr
& lp) {
if ((p = lp.p) != NULL)
p->AddRef();
}
~CComPtr() {if (p) p->Release();}
void Release() {if (p) p->Release(); p=NULL;}
operator T*() {return (T*)p;}
T& operator*() {_ASSERTE(p!=NULL); return *p; }
T** operator&() { _ASSERTE(p==NULL); return &p; }
T* operator->() { _ASSERTE(p!=NULL); return p; }
T* operator=(T* lp){return (T*)AtlComPtrAssign((IUnknown**)&p, lp);}
T* operator=(const CComPtr
& lp) {
return (T*)AtlComPtrAssign((IUnknown**)&p, lp.p);
}
bool operator!(){return (p == NULL);}
T* p;
};
template
class CComQIPtr
{
public:
typedef T _PtrClass;
CComQIPtr() {p=NULL;}
CComQIPtr(T* lp) {
if ((p = lp) != NULL)
p->AddRef();
}
CComQIPtr(const CComQIPtr& lp) {
if ((p = lp.p) != NULL)
p->AddRef();
}
CComQIPtr(IUnknown* lp) {
p=NULL;
if (lp != NULL)
lp->QueryInterface(*piid, (void **)&p);
}
~CComQIPtr() {if (p) p->Release();}
void Release() {if (p) p->Release(); p=NULL;}
operator T*() {return p;}
T& operator*() {_ASSERTE(p!=NULL); return *p; }
T** operator&() { _ASSERTE(p==NULL); return &p; }
T* operator->() {_ASSERTE(p!=NULL); return p; }
T* operator=(T* lp){return (T*)AtlComPtrAssign((IUnknown**)&p, lp);}
T* operator=(const CComQIPtr& lp) {
return (T*)AtlComPtrAssign((IUnknown**)&p, lp.p);
}
T* operator=(IUnknown* lp) {
return (T*)AtlComQIPtrAssign((IUnknown**)&p, lp, *piid);
}
bool operator!(){return (p == NULL);}
T* p;
};
//更新 修改上述代码,使之成为独立于ATL环境的纯c++ CComPtr类,主要是改写重载运算符函数operator=,实现如下:
T* operator=(T* lp){ASSERT(lp!=NULL);if(ISEqual(lp)) return p; p->release();lp->addref(); p=lp; return p;}检测是否为自赋值:BOOL ISEqual(IUnknown* pOther){ASSERT(lp); IUnknown pUnknown==NULL; p ->queryinterface(IID_IUnknown, (void**)&pUnknown);BOOL result=(pUnknown==pOther)?TRUE:FALSE; pUnknown->release; return result;}
T* operator=(const CComQIPtr& lp) {
ASSERT(&lp!=NULL);p=(T*)lp;if(p)p->addref();return p;}
T* operator=(IUnknown* lp) {
AASERT(lp); lp->queryinterface(IID_T,(void**)&p);ASSERT(p);return p);
}