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

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

C++中auto_ptr智能指针的⽤法详解
智能指针(auto_ptr) 这个名字听起来很酷是不是?其实auto_ptr 只是C++标准库提供的⼀个类模板,它与传统的new/delete控制内存相⽐有⼀定优势,但也有其局限。

本⽂总结的8个问题⾜以涵盖auto_ptr
的⼤部分内容。

auto_ptr是什么?
auto_ptr 是C++标准库提供的类模板,auto_ptr对象通过初始化指向由new创建的动态内存,它是这块内存的拥有者,⼀块内存不能同时被分给两个拥有者。

当auto_ptr对象⽣命周期结束时,其析构函数
会将auto_ptr对象拥有的动态内存⾃动释放。

即使发⽣异常,通过异常的栈展开过程也能将动态内存释放。

auto_ptr不⽀持new 数组。

C++中指针申请和释放内存通常采⽤的⽅式是new和delete。

然⽽标准C++中还有⼀个强⼤的模版类就是auto_ptr,它可以在你不⽤的时候⾃动帮你释放内存。

下⾯简单说⼀下⽤法。

<textarea cols="50" rows="15" name="code" class="cpp">
⽤法⼀: std::auto_ptr&lt;MyClass&gt;m_example(new MyClass());
⽤法⼆: std::auto_ptr&lt;MyClass&gt;m_example; m_example.reset(new MyClass());
⽤法三(指针的赋值操作): std::auto_ptr&lt;MyClass&gt;m_example1(new MyClass());
std::auto_ptr&lt;MyClass&gt;m_example2(new MyClass()); m_example2=m_example1;</textarea>
则C++会把m_example所指向的内存回收,使m_example1 的值为NULL,所以在C++中,应绝对避免把auto_ptr放到容器中。

即应避免下列代码:
vector<auto_ptr<MyClass>>m_example;
当⽤算法对容器操作的时候,你很难避免STL内部对容器中的元素实现赋值传递,这样便会使容器中多个元素被置位NULL,⽽这不是我们想看到的。

虽然,标准auto_ptr智能指针机制很多⼈都知道,但很少使⽤它。

这真是个遗憾,因为auto_ptr优雅地解决了C++设计和编码中常见的问题,正确地使⽤它可以⽣成健壮的代码。

本⽂阐述了如何正确运⽤
auto_ptr来让你的代码更加安全——以及如何避免对auto_ptr危险但常见的误⽤,这些误⽤会引发间断性发作、难以诊断的bug。

为什么称它为“⾃动”指针?auto_ptr只是众多可能的智能指针之⼀。

许多商业库提供了更复杂的智能指针,⽤途⼴泛⽽令⼈惊异,从管理引⽤的数量到提供先进的代理服务。

可以把标准C++ auto_ptr看作
智能指针的Ford Escort(elmar注:可能指福特的⼀种适合家居的车型):⼀个简易、通⽤的智能指针,它不包含所有的⼩技巧,不像专⽤的或⾼性能的智能指针那么奢华,但是它可以很好的完成许多普
遍的⼯作,它很适合⽇常性的使⽤。

auto_ptr所做的事情,就是动态分配对象以及当对象不再需要时⾃动执⾏清理。

这⾥是⼀个简单的代码⽰例,没有使⽤auto_ptr所以不安全:
<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&lt;T&gt; 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&lt;T&gt; pt2(pt1); // 使⽤auto_ptr就像我们以前使⽤简单指针⼀样,
最后,我们可以使⽤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&lt;T&gt; pt( new T(1) ); pt.reset( new T(2) ); // 删除由"new T(1)"分配出来的第⼀个T } // 最后pt出了作⽤域,第⼆个T也被删除了</textarea>
auto_ptr⽤法:
1. 需要包含头⽂件<memory>。

2. Constructor:explicit auto_ptr(X* p = 0) throw(); 将指针p交给auto_ptr对象托管。

3. Copy constructor:auto_ptr(const auto_ptr&) throw(); template<class Y> auto_ptr(const auto_ptr<Y>& a) throw(); 指针的托管权会发⽣转移。

4. Destructor: ~auto_ptr(); 释放指针p指向的空间。

5. 提供了两个成员函数 X* get() const throw(); //返回保存的指针
6. 对象中仍保留指针 X* release() const throw(); //返回保存的指针,对象中不保留指针
auto_ptr实现关键点:
1. 利⽤特点“栈上对象在离开作⽤范围时会⾃动析构”。

2. 对于动态分配的内存,其作⽤范围是程序员⼿动控制的,这给程序员带来了⽅便但也不可避免疏忽造成的内存泄漏,毕竟只有编译器是最可靠的。

3. auto_ptr通过在栈上构建⼀个对象a,对象a中wrap了动态分配内存的指针p,所有对指针p的操作都转为对对象a的操作。

⽽在a的析构函数中会⾃动释放p的空间,⽽该析构函数是编译器⾃动调⽤的,
⽆需程序员操⼼。

多说⽆益,看⼀个最实⽤的例⼦:
<textarea cols="50" rows="15" name="code" class="cpp">#include &lt;iostream&gt; #include &lt;memory&gt; using namespace std; class TC { public: TC(){cout&lt;&lt;"TC()"&lt;&lt;endl;} ~TC(){cout&lt;&lt;"~TC()"&lt;&lt;endl;} }; void foo(bool isThrow) { auto_ptr& // ⽅法2 //TC *pTC = new TC;
// ⽅法1 try { if(isThrow) throw "haha"; } catch(const char* e) { //delete pTC; // ⽅法1 throw; } //delete pTC; // ⽅法1 } int main() { try { foo(true); } catch(...) { cout&lt;&lt;"caught"&lt;&lt;endl; } system("pause"); }</textarea>
1. 如果采⽤⽅案1,那么必须考虑到函数在因throw异常的时候释放所分配的内存,这样造成的结果是在每个分⽀处都要很⼩⼼的⼿动 delete pTC;。

2. 如果采⽤⽅案2,那就⽆需操⼼何时释放内存,不管foo()因何原因退出,栈上对象pTC的析构函数都将调⽤,因此托管在之中的指针所指的内存必然安全释放。

⾄此,智能指针的优点已经很明了了。

但是要注意使⽤中的⼀个陷阱,那就是指针的托管权是会转移的。

例如在上例中,如果 auto_ptr<TC> pTC(new TC); auto_ptr<TC> pTC1=pTC; 那么,pTC1将拥有该指针,⽽pTC没有了,如果再⽤
pTC去引⽤,必然导致内存错误。

要避免这个问题,可以考虑使⽤采⽤了引⽤计数的智能指针,例如boost::shared_ptr等。

auto_ptr不会降低程序的效率,但auto_ptr不适⽤于数组,auto_ptr根本不可以⼤规模使⽤。

shared_ptr也要配合
weaked_ptr,否则会很容易触发循环引⽤⽽永远⽆法回收内存。

理论上,合理使⽤容器加智能指针,C++可以完全避免内存泄露,效率只有微不⾜道的下降(中型以上程序最多百分之⼀)。

以上所述是⼩编给⼤家介绍的C++中auto_ptr智能指针的⽤法详解,希望对⼤家有所帮助,如果⼤家有任何疑问请给我留⾔,⼩编会及时回复⼤家的。

在此也⾮常感谢⼤家对⽹站的⽀持!。

相关文档
最新文档