标签:
std::auto_ptr<ClassA> pa(new ClassA);
非常多人听说过标准auto_ptr智能指针机制,但并非每一个人都天天使用它。这真是个遗憾。由于auto_ptr优雅地攻克了C++设计和编码中常见的问题,正确地使用它能够生成健壮的代码。本文阐述了怎样正确运用auto_ptr来让你的代码更加安全——以及怎样避免对auto_ptr危急但常见的误用,这些误用会引发间断性发作、难以诊断的bug。
1.为什么称它为“自己主动”指针?
auto_ptr仅仅是众多可能的智能指针之中的一个。很多商业库提供了更复杂的智能指针。用途广泛而令人惊异,从管理引用的数量到提供先进的代理服务。能够把标准C++ auto_ptr看作智能指针的Ford Escort(elmar注:可能指福特的一种适合家居的车型):一个简易、通用的智能指针,它不包括全部的小技巧。不像专用的或高性能的智能指针那么奢华。可是它能够非常好的完毕很多普遍的工作,它非常适合日常性的使用。
auto_ptr所做的事情,就是动态分配对象以及当对象不再须要时自己主动运行清理。这里是一个简单的代码演示样例,没有使用auto_ptr所以不安全:
// 演示样例 1(a): 原始代码
//
void f()
{
T* pt( new T );
/*...很多其它的代码...*/
delete pt;
}
我们大多数人每天写类似的代码。
假设f()函数仅仅有三行而且不会有不论什么意外,这么做可能挺好的。
可是假设f()从不运行delete语句。或者是因为过早的返回。或者是因为运行函数体时抛出了异常,那么这个被分配的对象就没有被删除。从而我们产生了一个经典的内存泄漏。
能让演示样例1(a)安全的简单办法是把指针封装在一个“智能的”类似于指针的对象里,这个对象拥有这个指针而且能在析构时自己主动删除这个指针所指的对象。由于这个智能指针能够简单的当成一个自己主动的对象(这就是说,它出了作用域时会自己主动毁灭)。所以非常自然的把它称之为“智能”指针:
// 演示样例 1(b): 安全代码, 使用了auto_ptr
//
void f()
{
auto_ptr<T> pt( new T );
/*...很多其它的代码...*/
} // 酷: 当pt出了作用域时析构函数被调用。
// 从而对象被自己主动删除
如今代码不会泄漏T类型的对象。无论这个函数是正常退出还是抛出了异常。由于pt的析构函数总是会在出栈时被调用。清理会自己主动进行。
最后,使用一个auto_ptr就像使用一个内建的指针一样easy。并且假设想要“撤销”资源,又一次採用手动的全部权,我们仅仅要调用release():
// 演示样例 2: 使用一个 auto_ptr
//
void g()
{
T* pt1 = new T;
// 如今。我们有了一个分配好的对象
// 将全部权传给了一个auto_ptr对象
auto_ptr<T> pt2( pt1 );
// 使用auto_ptr就像我们曾经使用简单指针一样
*pt2 = 12; // 就像 "*pt1 = 12;"
pt2->SomeFunc(); // 就像 "pt1->SomeFunc();"
// 用get()来获得指针的值
assert( pt1 == pt2.get() );
// 用release()来撤销全部权
T* pt3 = pt2.release();
// 自己删除这个对象,由于如今
// 没有不论什么auto_ptr拥有这个对象
delete pt3;
} // pt2不再拥有不论什么指针,所以不要
// 试图删除它...ok。不要反复删除
最后,我们能够使用auto_ptr的reset()函数来重置auto_ptr使之拥有还有一个对象。假设这个auto_ptr已经拥有了一个对象。那么,它会先删除已经拥有的对象,因此调用reset()就如同销毁这个auto_ptr,然后新建一个并拥有一个新对象:
// 演示样例 3: 使用reset()
//
void h()
{
auto_ptr<T> pt( new T(1) );
pt.reset( new T(2) );
// 删除由"new T(1)"分配出来的第一个T
} // 最后。pt出了作用域。
// 第二个T也被删除了
#include <utility> #include <iostream> using namespace std; class A { public: A() { id = ++count; cout << "create A" << id << "\n"; } ~A() { cout << "destroy A" << id << "\n"; } private: static int count; int id; }; int A::count = 0; /*调用该函数会丢失掉全部权*/ void sink(auto_ptr<A> a) { cout << "Enter sink()\n"; } /*调用该函数会创建对象,并获取全部权*/ auto_ptr<A> create() { cout << "Enter create()\n"; auto_ptr<A> a(new A()); return a; } int main(int argc, char *argv[]) { auto_ptr<A> a1 = create(); auto_ptr<A> a2 = a1; /*转移全部权,此时a1无效了*/ auto_ptr<A> a3(new A()); cout << "Exit create()\n"; sink(a2);/*丢失全部权,会发现a2的释放在sink函数中进行*/ cout << "Exit sink()\n"; return 0; }
怎样防止函数调用转移全部权呢?
在《the c++ standard library》page43里有提到,採用const reference,这样形參不会交出全部权。由于无法令 const reference交出全部权!!
3,使用auto_ptr作为成员变量,以避免资源泄漏。
比方,假设该类有2个成员变量,指向两个资源。在构造函数中申请资源A成功,但申请资源B失败,则构造函数失败。那么析构函数不会被调用。那么资源A则泄漏。
为了解决问题,我们能够利用auto_ptr代替普通指针作为成员变量,这样首先调用成功的成员变量的构造函数肯定会调用其析构函数,那么就能够避免资源泄漏问题。
4,不要误用auto_ptr
1)auto_ptr不能共享全部权,即不要让两个auto_ptr指向同一个对象。
2)auto_ptr不能指向数组。由于auto_ptr在析构的时候仅仅是调用delete,而数组应该要调用delete[]。
3)auto_ptr仅仅是一种简单的智能指针。如有特殊需求。须要使用其它智能指针,比方share_ptr。
4)auto_ptr不能作为容器对象,STL容器中的元素常常要支持拷贝。赋值等操作,在这过程中auto_ptr会传递全部权。那么source与sink元素之间就不等价了。
參考:
1 http://www.cnblogs.com/qytan36/archive/2010/06/28/1766555.html
2 http://blog.csdn.net/cyblueboy83/article/details/1792463
3 c++ primer page591~
版权声明:本文博客原创文章,博客,未经同意,不得转载。
标签:
原文地址:http://www.cnblogs.com/gcczhongduan/p/4726083.html