C++ auto_ptr总结
auto_ptr是当前标准C++标准库中提供的一种智能指针,auto_ptr的出现,最初主要是为了解决“裸指针被异常抛出时发生资源泄漏”的问题。如下:
try
{
int * p = new int(0);
doSomeThing(p);
delete p;
}
Catch
{
doSomeThingForError();
}
当doSomeThing中异常抛出时,将跳过delete 而执行catch中的
p
doSomeThingForError(),那么之前分配的整形变量资源不会被释放,从而导致资源泄露。
auto_ptr的实现原理其实就是\"resource acquisition is initialization\"(RAII,资源获取即初始化),它在构造的时候获取资源,在析构的时候释放资源,并进行相关指针操作的重载,使用起来就像普通的指针。
以下是一个auto_ptr的实现版本,仔细阅读以便理解上述加红部分叙述。
namespace std
{
template class auto_ptr { private: T* ap; public: // constructor & destructor ----------------------------------- (1) explicit auto_ptr (T* ptr = 0) throw() : ap(ptr){} ~auto_ptr() throw() { delete ap;} // Copy & assignment --------------------------------------------(2) auto_ptr (auto_ptr& rhs) throw() :ap(rhs.release()) {} template auto_ptr (auto_ptr auto_ptr& operator= (auto_ptr& rhs) throw() { reset(rhs.release()); return *this; } template auto_ptr& operator= (auto_ptr { reset(rhs.release()); return *this; } // Dereference----------------------------------------------------(3) T& operator*() const throw() { return *ap;} T* operator->() const throw() { return ap;} // Helper functions------------------------------------------------(4) T* get() const throw() { return ap;} // release ownership T* release() throw() { T* tmp(ap); ap = 0; return tmp; } // reset value void reset (T* ptr=0) throw() { if (ap != ptr) { delete ap; ap = ptr; } } template operator auto_ptr { return auto_ptr }; } 注意上述代码加红处,它们体现了:构造的时候获取资源,在析构的时候释放资源,并进行相关指针操作的重载。 事实上,auto_ptr就是一个类,在这个类构造时根据传入的裸指针获得资源,并在auto_ptr类对象生命周期结束时调用其析构函数自动释放裸指针指向的资源。 以下是auto_ptr的使用示例: int* p = new int(0); auto_ptr //从此我们不必关心应该何时释放p,也不用担心发生异常会有内存泄漏。因为在ap生命周期结束时会在其析构函数中自动释放裸指针p。 这里我们有几点要注意: 1) 两个auto_ptr不能同时拥有同一个对象。 因为auto_ptr析构的时候肯定会删除他所拥有的那个对象,所有我们就要注意了,一个萝卜一个坑, int* p = new int(0); auto_ptr auto_ptr 因为ap1与ap2都认为指针p是归它管的,在析构时都试图删除p, 两次删除同一个对象的行为在C++标准中是未定义的。所以我们必须防止这样使用auto_ptr. auto_ptr与boost库中的share_ptr不同的,auto_ptr没有考虑引用计数,因此一个对象只能由一个auto_ptr所拥有,在给其他auto_ptr赋值的时候,会转移这种拥有关系。 2) 不应该用auto_ptr来管理一个数组指针 int* pa = new int[10]; auto_ptr 因为auto_ptr的析构函数中删除指针用的是delete,而不是delete [],所以我们不应该用auto_ptr来管理一个数组指针。 3)auto_ptr被拷贝或被赋值后,其已经失去对原对象的所有权 这个时候,对这个auto_ptr的提领(dereference)操作是不安全的。如下: int* p = new int(0); auto_ptr auto_ptr cout<<*ap1; //错误,此时ap1只剩一个null指针在手了 4)auto_ptr作为函数参数按值传递是一定要避免的 在函数调用过程中在函数的作用域中会产生一个局部对象来接收传入的auto_ptr(拷贝构造),这样,传入的实参auto_ptr就失去了其对原对象的所有权,而该对象会在函数退出时被局部auto_ptr删除。如下: void f(auto_ptr auto_ptr f(ap1); cout<<*ap1; //错误,经过f(ap1)函数调用,ap1已经不再拥有任何对象了。因为这种情况太隐蔽,太容易出错了, 所以auto_ptr作为函数参数按值传递是一定要避免的。 5)auto_ptr不能被用在stl标准容器中 因为auto_ptr不具有值语义(value semantic), 所以auto_ptr不能被用在stl标准容器中。所谓值语义,是指符合以下条件的类型(假设有类A): A a1; A a2(a1); A a3; a3 = a1; 那么 a2 == a1, a3 == a1 很明显,auto_ptr不符合上述条件,而我们知道stl标准容器要用到大量的拷贝赋值操作,并且假设其操作的类型必须符合以上条件。
因篇幅问题不能全部显示,请点此查看更多更全内容