ATL提供了CAutoPtr, CAutoVectorPtr, CAutoPtrArray, and CAutoPtrList,它们具有类似auto_ptr功能,而没有抛出异常,并且不需要借助于CRT库。
The CAutoPtr and CAutoVectorPtr Classes
例子:
STDMETHODIMP CMyClass::SomeFunc() { CFoo* pFoo = new Foo(); // instantiate C++ class CAutoPtr<CFoo> spFoo(pFoo); // take ownership of pFoo spFoo->DoSomeFoo(); // ... do other things with spFoo } // CAutoPtr deletes pFoo instance // when spFoo goes out of scope
下面以CAutoPtr为样板,其他智能指针功能类似
Constructors and Destructor
CAutoPtr() : m_p( NULL ) { } template< typename TSrc > CAutoPtr( CAutoPtr< TSrc >& p ) { m_p = p.Detach(); // Transfer ownership } CAutoPtr( CAutoPtr< T >& p ) { m_p = p.Detach(); // Transfer ownership } explicit CAutoPtr( T* p ) : m_p( p ) { }
注意4th类型,p可以为派生类
class CAnimal { ... }; class CDog : public CAnimal { ... }; // ... CDog* pDog = new CDog(); CAutoPtr<CAnimal> spAnimal(pDog);
~CAutoPtr() { Free(); } void Free() { delete m_p; m_p = NULL; }
CAutoPtr Operators
template< typename TSrc > CAutoPtr< T >& operator=( CAutoPtr< TSrc >& p ) { if(m_p==p.m_p) { ATLASSERT(FALSE); } else { Free(); Attach( p.Detach() ); // Transfer ownership } return( *this ); } CAutoPtr< T >& operator=( CAutoPtr< T >& p ) { if(*this==p) { if(this!=&p) { ATLASSERT(FALSE); p.Detach(); } else { } } else { Free(); Attach( p.Detach() ); // Transfer ownership } return( *this ); }
不管采用何种形态,首先检查指针是否指向同一个实例,然后Free(),再用Detach()转移释放权,避免多次delete
注意第一种形态,TSrc可以为T的衍生类,例子:
class CAnimal { ... }; class CDog : public CAnimal { ... }; // ... // instantiate a CAnimal CAutoPtr<CAnimal> spAnimal(new CAnimal()); // instantiate a CDog CAutoPtr<CDog> spDog(new CDog()); // CAnimal instance freed here spAnimal = spDog; // ... CDog instance will be freed when spAnimal // goes out of scope
类重新定义了->操作:
operator T*() const { return( m_p ); } T* operator->() const { ATLASSERT( m_p != NULL ); return( m_p ); }
例子:
class CDog { public: void Bark() {} int m_nAge; }; CAutoPtr<CDog> spDog(new Dog); spDog->Bark(); spDog->m_nAge += 5;
比较操作符:
bool operator!=(CAutoPtr<T>& p) const { return !operator==(p); } bool operator==(CAutoPtr<T>& p) const { return m_p==p.m_p; }
CAutoVectorPtr
和CAutoPtr相比,有多点不同:
CAutoVectorPtr不能使用派生类指针进行赋值
CAutoVectorPtr使用Allocate进行集合构造,类似于new[]:
bool Allocate( size_t nElements ) { ATLASSERT( m_p == NULL ); ATLTRY( m_p = new T[nElements] ); if( m_p == NULL ) { return( false ); } return( true ); }
例子:
class CAnimal { public: void Growl() {} }; // each instance is of type CAnimal CAutoVectorPtr<CAnimal> spZoo; // allocate and initialize 100 CAnimal's spZoo.Allocate(100);
注意,该类没有重载->操作符,所以下面的代码是错误的:
spZoo->Growl(); // wrong! can't do this => doesn't make sense
而且,ATL并没有重载operator[],所以必须要使用下面的形式:
((CAnimal*)spZoo)[5].Growl();
而且,ATL只接受带有默认构造函数的类,所以下面的代码是错误的:
class CAnimal {
public:
CAnimal(int nAge) : m_nAge(nAge) {}
void Growl() {}
private:
int m_nAge;
}
CAutoVectorPtr<CAnimal> spZoo;
spZoo.Allocate(100); // won't compile => no default constructor
注意,析构函数使用了delete[]来释放内存,对应的只能是Allocate(),所以如果用户使用了Attach(),就会造成麻烦:
class CAnimal {};
// allocate only a single instance
CAnimal* pAnimal = new Animal;
CAutoVectorPtr<CAnimal> spZoo;
// wrong, wrong!!! pAnimal is not a collection
spZoo.Attach(pAnimal)