很多人听说过标准auto_ptr智能指针机制,但并不是每个人都天天使用它。这真是个遗憾,因为auto_ptr优雅地解决了C++设计和编码中常见的问题,正确地使用它可以生成健壮的代码。本文阐述了如何正确运用auto_ptr来让你的代码更加安全——以及如何避免对auto_ptr危险但常见的误用,这些误用会引发间断性发作、难以诊断的bug。
为什么称它为“自动”指针?
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就像使用一个内建的指针一样容易,而且如果想要“撤销”资源,重新采用手动的所有权,我们只要调用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也被删除了
PS:再贴一个
http://cns_tech.blogbus.com/logs/4628846.html
#include
#include
#include
using namespace std;
int main(int argc, char* argv[])
{
auto_ptr api ,api2;
api = auto_ptr( new int(10) );
cout<<"api:"<<*api<<endl;
/*
api对象的布局:
一个int数表示该对象是否有效。(==1有效,==0无效)
一个指针 指向int数据(因为你在声明api时已经说了它时指向int的)
*/
api2 = api; //传递性:执行完本句之后,api无效,同时api2有效,api2的另一个字段指向int
auto_ptr aps1,aps2;
aps1 = auto_ptr(new string("pig") );
cout<<"aps1:"<<*aps1<
return 0;
}
vc6的说明:auto_ptr
template class auto_ptr
{
public:
typedef T element_type;
explicit auto_ptr(T *p = 0) throw();
auto_ptr(const auto_ptr& rhs) throw();
auto_ptr& operator=(auto_ptr& rhs) throw();
~auto_ptr();
T& operator*() const throw();
T *operator->() const throw();
T *get() const throw();
T *release() const throw();
};
The class describes an object that stores a pointer to an allocated object of type T. The stored pointer must either be null or designate an object allocated by a new expression. The object also stores an ownership indicator. An object constructed with a non-null pointer owns the pointer. It transfers ownership if its stored value is assigned to another object. The destructor for auto_ptr deletes the allocated object if it owns it. Hence, an object of class auto_ptr ensures that an allocated object is automatically deleted when control leaves a block, even via a thrown exception.
//好了,估计说了这么多 ,应该知道 auto_ptr的功能和不足了。
//再看看以下我转过来的文章
STL中的auto_ptr指针是为了解决内存泄漏问题而设计的。它严格限制了指针拥有对指向对象的所有权。auto_ptr指针和普通指针的差别在于对指向对象所有权的处理不同。auto_ptr指针是“传递”所有权,而普通指针是“共享”所有权。看下面例子:
std::auto_ptr p1(new int(24));
std::auto_ptr p2;
int *q1 = new int(12);
int *q2;
p2 = p1;
q2 = q1;
经过两次赋值后,对于auto_ptr,p1为NULL,*p2为24;对于普通指针,*p1, *p2均为12。第一次赋值,p1把指向对象的所有权传递给了p2, p1不再拥有指向对象的所有权。而第二次赋值,q2和q1共享了对同一对象的所有权。因此,对于auto_ptr,一个对象只可能被一个智能指针指向,这样可有效避免内存泄漏问题。但是同时会引起新问题。看下面例子:
template
void BadPrint(std::auto_ptr p)
{
if (p.get() == NULL)
{
std::cout<
}
else
{
std::cout<<*p;
}
}
然后我如下使用BadPrint函数:
std::auto_ptr q(new int(18));
BadPrint(q);
*q = 12;
该程序并未像我们所期望的一样:*q的值为12,而是会出现runtime error,why?因为我们把q作为函数参数传给了BadPrint,因此传递完成后q不再拥有对指向对象的所有权,而函数内部的局部变量p会接管q所指向对象的所有权,当函数执行完毕退出时,p的生命期截止同时delete所指向对象。因此q实际变为NULL,所以出错。如何避免出错?使用auto_ptr的引用?即 void BadPrint(std::auto_ptr &p)。这是相当糟糕的一种做法。对智能指针使用引用混淆了所有权的问题。它导致所有权有可能被传递了,也可能没有被传递。无论如何应当避免对auto_ptr使用引用。
可见智能指针并非对任何情况都智能。使用auto_ptr要知道:
1. 智能指针不能共享指向对象的所有权
2. 智能指针不能指向数组。因为其实现中调用的是delete而非delete[]
3. 智能指针不是万能的
4. 智能指针不能作为容器类的元素。
例如:
template
void container::insert(const T &value)
{
..........
X = value;
..........
}
事实上在stl中,所有的container要内部拷贝所传参数的值时都是传的const类型的值。因此无法用auto_ptr传进去。
假定有一个动态分配的int空间,则在一个时刻只能有一个auto_ptr指针指向他!这就是所有权的独占性。