- 设计 auto_ptr目的
auto_ptr是一种智能型指针,帮助程序员防止“被异常抛出时发生资源泄露”。auto_ptr只是针对某个特定问题而设计,对于其他问题,auto_ptr无能为力。
如果一开始获取的资源被绑定于局部对象,那么当函数执行完毕退出时,它们的析构函数被调用,从而自动释放这些资源。然而如果资源是以显式方法获得,而且没有被绑定在任何对象身上,那么必须以显式方法释放。
比如用new和delete来产生和销毁对象:
void foo()
{
ClassA *ptr = new ClassA;
...
delete ptr;
}
使用new创建一个新对象并在函数结束时用delete释放掉,这样函数会顺利结束并且不会存在内存泄露的问题。但是有时我们会忘记写delete而引发问题,同时如果在函数中间存在return语句时会引发更大问题。异常一旦出现,函数将立刻退出,根本不会调用函数尾端的delete语句,这样就会造成内存遗失。
解决这个问题的常用办法是捕捉异常
void foo()
{
ClassA* ptr = new ClassA;
try
{
... //perform some operation
}
catch (...)
{
//for any exception
delete ptr;
throw;
}
delete ptr;
}
为了在异常发生时处理对象的删除工作,代码将会变得很繁琐,如果有多个对象,则需要对每一个对象都执行此操作。
如果使用智能型指针来解决此问题就会非常简单。这个智能型指针应保证无论在何种情形下只要自己被摧毁,就一定连带释放其所指资源。而由于智能型指针本身就是局域变量,所以无论是正常退出还是异常退出,它就一定会被销毁。
auto_ptr就是这种指针:它是“它所指对象”的拥有者,同时auto_ptr要求一个对象只能有一个拥有者。
#include<memory>
void foo()
{
std::auto_ptr<ClassA> ptr(new ClassA);
...
}
auto_ptr<>不允许使用一般指针惯用的赋值初始化方式,必须直接使用数值来完成初始化
std::auto_ptr<ClassA> ptr1(new ClassA); //ok
std::auto_ptr<ClassA> ptr2 = new ClassA; //ERROR
- auto_ptr拥有权的转移
auto_ptr界定的是一种严格的拥有权观念,绝对不允许出现多个auto_ptr同时拥有一个对象的情况。
这个条件导致了一个问题:auto_ptr的拷贝构造函数和赋值操作符应该怎样运行呢?
解决办法是:令auto_ptr的拷贝构造函数和赋值操作符将对象拥有权交出去。
//初始化
std::auto_ptr<ClassA> ptr1(new ClassA);
//拷贝构造函数
std::auto_ptr<ClassA> ptr2(ptr1);
//赋值操作
std::auto_ptr<ClassA>ptr2;
ptr2=ptr1;
在第一个语句中,ptr1拥有了那个new出来的对象,在第二语句中,拥有权由ptr1转交给ptr2。此后ptr2就拥有了那个new出来的对象,而ptr1不再拥有它。
第三个赋值语句也是同样的道理,需要注意的是如果ptr2被赋值之前拥有另外一个对象,执行赋值操作时首先会调用delete,先将ptr2指向的对象删除掉然后再将ptr1赋值给ptr2。
这里我们还需要注意一个问题就是,只要发生了拥有权转移,先前的拥有者就失去了拥有权,这时它只剩了一个NULL指针。那么如何保证使用者重新解引用这个空指针呢?auto_ptr规定只能使用auto_ptr作为另外一个auto_ptr的初值,普通指针不可以。
- auto_ptr的起点和终点
拥有权的转移使得某个函数可以利用auto_ptr将拥有权转交给另一个函数,可能会出现两种情况:
①某函数是数据的终点。如果auto_ptr以传值的方式被当作一个参数传递给某函数,此时被调用端的参数获得了这个auto_ptr的拥有权,如果函数不再将它传递出去,它所指的对象就会在函数退出时被删除。
②某函数是数据的起点。当一个auto_ptr被返回,其拥有权便被转交给调用端了。
考虑到auto_ptr的概念,可以用const reference像函数传递拥有权,这里的const并非意味不能更改auto_ptr所拥有的对象,而是意味着不能更改auto_ptr的拥有权。
- auto_ptr的错误使用
①auto_ptr之间不能共享拥有权
一个auto_ptr不能指向另一个auto_ptr所拥有的对象,否则,当第一个指针删除该对象后,另一个指针就会指向一个已经被销毁的对象,此时如果再使用那个指针进行读写操作,就会引发错误。
②不存在针对array而设计的auto_ptr
auto_ptr不可以指向array,因为auto_ptr是通过delete而不是delete[ ]来释放其所拥有的对象。
③auto_ptr并不是一个全能的、“四海通用”型的指针
并非任何适用智能型指针的地方,都适用auto_ptr。
④auto_ptr不满足STL容器对其元素的要求
由于在拷贝和赋值动作之后,原本的auto_ptr和新产生的auto_ptr并不相等。原本的auto_ptr会交出拥有权,而不是拷贝给新的auto_ptr。