C++中auto_ptr智能指针的用法详解

2020-01-06 15:29:27刘景俊


<textarea cols="50" rows="15" name="code" class="cpp">// 示例1(a):原始代码 void f() { T* pt( new T ); /*...更多的代码...*/ delete pt; }</textarea>

我们大多数人每天写类似的代码。如果f()函数只有三行并且不会有任何意外,这么做可能挺好的。但是如果f()从不执行delete语句,或者是由于过早的返回,或者是由于执行函数体时抛出了异常,那么这个被分配的对象就没有被删除,从而我们产生了一个经典的内存泄漏。

能让示例1(a)安全的简单办法是把指针封装在一个“智能的”类似于指针的对象里,这个对象拥有这个指针并且能在析构时自动删除这个指针所指的对象。因为这个智能指针可以简单的当成一个自动的对象(这就是说,它出了作用域时会自动毁灭),所以很自然的把它称之为“智能”指针:


<textarea cols="50" rows="15" name="code" class="cpp">// 
示例1(b):安全代码,使用了auto_ptr void f() { auto_ptr<T> pt( new T ); /*...更多的代码...*/ } // 酷:当pt出了作用域时析构函数被调用,从而对象被自动删除</textarea>

现在代码不会泄漏T类型的对象,不管这个函数是正常退出还是抛出了异常,因为pt的析构函数总是会在出栈时被调用,清理会自动进行。

最后,使用一个auto_ptr就像使用一个内建的指针一样容易,而且如果想要“撤销”资源,重新采用手动的所有权,我们只要调用release()。


<textarea cols="50" rows="15" name="code" class="cpp">// 示例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,不要重复删除 </textarea>

最后,我们可以使用auto_ptr的reset()函数来重置auto_ptr使之拥有另一个对象。如果这个auto_ptr已经拥有了一个对象,那么,它会先删除已经拥有的对象,因此调用reset()就如同销毁这个auto_ptr,然后新建一个并拥有一个新对象:

 


<textarea cols="50" rows="15" name="code" class="cpp">//
示例 3:使用reset() void h() { auto_ptr<T> pt( new T(1) ); pt.reset( new T(2) ); // 删除由"new T(1)"分配出来的第一个T } // 最后pt出了作用域,第二个T也被删除了</textarea>