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)
ATL中的CAutoPtr和CAutoVectorPtr是智能指针实现,不抛异常且不依赖CRT库。CAutoPtr在构造、析构及操作符中确保正确释放内存,支持派生类。CAutoVectorPtr则不允许派生类赋值,使用Allocate进行集合构造,但未重载->和operator[],仅接受有默认构造函数的类,使用Delete[]释放内存,需要注意Attach()使用的情景。

1万+

被折叠的 条评论
为什么被折叠?



