(转载请注明原创于潘多拉盒子)

  智能指针(Smart Pointer)是C++非常重要的特性。考虑如下一段使用简单指针(Plain Pointer)的代码:

A* a = new A();
B* b = new B();
......
if (condition1)
{
// return之前必须delete所有new出来的对象
delete a;
delete b;
return true;
}
......
if (condition2)
{
// return之前必须delete所有new出来的对象
delete a;
delete b;
return true;
}
.......
if (condition3)
{
// throw 之前必须delete所有new出来的对象
delete a;
delete b;
throw std::exception("bad condition3");
} // 有异常必须catch,在rethrow之前delete所有new出来的对象
try
{
......
}
catch (...) // 三个点“...”用于此处捕捉所有异常
{
delete a;
delete b;
throw; // rethrow
}

  这种方式非常繁琐,也很容易犯错误(error-prone)。有没有一种方法,能管理new出来的对象,并且在return/throw/异常发生的时候自动释放这些对象呢?按照《C++的优秀特性3:构造函数和析构函数》的介绍,有一种借助构造函数和析构函数实现的模版类,可以实现这样的功能。这就是智能指针。比如标准库STL中实现了一种智能指针std::auto_ptr。有了这种智能指针,前面的程序就简单了:

std::auto_ptr<A> a(new A());
std::auto_ptr<B> b(new B());
......
a->foo();  // 像普通指针一样使用
(*b).bar();  // 像普通指针一样使用
if (condition1)
{
// return之前无需delete所有new出来的对象
return true;
}
......
if (condition2)
{
// return之前无需delete所有new出来的对象
return true;
}
.......
if (condition3)
{
// throw 之前无需delete所有new出来的对象
throw std::exception("bad condition3");
} // 有异常不处理的时候也不用catch和rethrow了

  一个智能指针指向一个对象叫做这个指针持有这个对象,也就是指针是这个对象的持有者。持有者负责在适当的时机释放持有的对象。常用的智能指针有3种:

  1. 单持有者,e.g. std::auto_ptr。单持有者保证每个new出来的对象只有一个持有者,单这种持有关系可以转移,转移之后原持有者不再持有对象。
  2. 局部持有者,e.g. boost::scoped_ptr。类似单持有者,单持有关系无法转移。这决定了这种持有关系不可能脱离当前的作用域(scope),因此得名。
  3. 共享持有者,e.g. boost::shared_ptr。一个对象可以被一个或多个这样的共享持有者持有,持有关系可以转移,转移之后原持有者继续持有该对象,直到原持有者被析构。当一个对象的最后一个持有者析构时,持有的对象被析构。

在实际中,由于#1(单持有者)的持有关系可以转移,常常是造成麻烦,而应用场景跟#2(局部持有者)又很接近,因此Google C++规范中禁止使用auto_ptr,而建议使用scoped_ptr。共享持有者是很常用的,基本上适用于大多数的简单指针应用的情况。但是,由于shared_ptr是为共享持有关系设计的,因此为了和scoped_ptr区分,在scoped_ptr适用的场景中,不要适用shared_ptr。

  实际中常见的一种错误是,智能指针持有了不该持有的对象。比如:

std::string name = "ZHANG San";
std::auto_ptr<std::string> nameHolder(&name); // 持有了不是new出来的对象,会导致segmentation fault

这其实是一种混用持有关系的问题。这可以简单的归纳为以下几种情况:

  1. 直接定义在栈上或data区的变量,不需要delete的。
  2. new出来的对象(在堆上),但程序员自己delete的。
  3. 不同类型的智能指针持有的对象。

这几种持有情况互相不能混用,否则会segmentation fault。

 

C++的优秀特性6:智能指针的更多相关文章

  1. C++11 新特性之智能指针(shared_ptr, unique_ptr, weak_ptr)

    这是C++11新特性介绍的第五部分,涉及到智能指针的相关内容(shared_ptr, unique_ptr, weak_ptr). shared_ptr shared_ptr 基本用法 shared_ ...

  2. C++的优秀特性4:指针

    (转载请注明原创于潘多拉盒子) 其实指针不是C++的特性,而是地地道道的C的特性.有人说C++继承了C的指针,实在是败笔,造成内存泄漏云云,纯粹是不懂.可以这么说,如果没有指针,C++会逊色很多,应用 ...

  3. C++新特性---智能指针

    智能指针:     为什么需要智能指针?         1. malloc出来的空间,没有进行释放,存在内存泄漏的问题.          2. 异常安全问题.如果在malloc和free之间如果存 ...

  4. 利用模板和C++11特性实现的智能指针-作用同share_ptr

    根据C++11特性实现,基本上实现了同SharePtr同样的功能,有时间继续优化.之前一直以为引用计数是一个静态的int类型,实际上静态值是不可以的.之前项目中总是不太习惯使用智能指针.通过自实现的方 ...

  5. 【C++11新特性】 C++11智能指针之weak_ptr

    如题,我们今天要讲的是C++11引入的三种智能指针中的最后一个:weak_ptr.在学习weak_ptr之前最好对shared_ptr有所了解.如果你还不知道shared_ptr是何物,可以看看我的另 ...

  6. C++11特性 - Smart Pointers 智能指针

    已经有成千上万的文章讨论这个问题了,所以我只想说:现在能使用的,带引用计数,并且能自动释放内存的智能指针包括以下几种:         unique_ptr: 如果内存资源的所有权不需要共享,就应当使 ...

  7. 智能指针 - 现代C++新特性总结

    C++98中的智能指针通过一个模板类auto_ptr来实现,new操作符返回的指针可以交由它来管理,程序员不用再显式的调用delete,这在一定程度上避免了堆内存忘记释放的问题:不过auto_ptr有 ...

  8. 智能指针shared_ptr新特性shared_from_this及weak_ptr

    enable_shared_from_this是一个模板类,定义于头文件<memory>,其原型为: template< class T > class enable_shar ...

  9. [C++11新特性] 智能指针详解

    动态内存的使用很容易出问题,因为确保在正确的时间释放内存是极为困难的.有时我们会忘记释放内存产生内存泄漏,有时提前释放了内存,再使用指针去引用内存就会报错. 为了更容易(同时也更安全)地使用动态内存, ...

随机推荐

  1. 转:移动开发中一些bug及解决方案

    网页开发要面对各种各样的浏览器,让人很头疼,而移动开发中,你不但要面对浏览器,还要面对各种版本的手机,iOS好一点,而安卓就五花八门了,你可能在开发中也被它们折磨过,或者正在被它们折磨,我在这里说几个 ...

  2. HEAD

    Branches are just pointers to commits Every branch is simply a named pointer to a commit. A special ...

  3. lookupedit清空选择 z

    lookupedit绑定数据,选择以后.怎么点击按钮使lookupedit回到初始位置,即nulltext的值.注意,是点击按钮,不是按默认的CTRL+DELETE. txtKHXX.EditValu ...

  4. API指南----application

    <application android:allowTaskReparenting=["true" | "false"]    android:allow ...

  5. Loadrunner常用的分析要点都有哪些

    提供了生产负载的虚拟用户运行状态的相关信息,可以帮助我们了解负载生成的结果. Rendezvous(负载过程中集合点下的虚拟用户): 当设置集合点后会生成相关数据,反映了随着时间的推移各个时间点上并发 ...

  6. 二叉树单色路径最长&&穿珠子

    对树的操作,特别理解递归的好处. //对于一棵由黑白点组成的二叉树,我们需要找到其中最长的单色简单路径,其中简单路径的定义是从树上的某点开始沿树边走不重复的点到树上的 //另一点结束而形成的路径,而路 ...

  7. 《Java数据结构与算法》笔记-CH4-4循环队列

    /** * 循环队列 */ class Queue { private int maxSize; private long[] queue; private int front; private in ...

  8. HDU ACM 2121 Ice_cream’s world II (无根最小树形图)

    [解题思路]这题先看了NotOnlySuccess的解题思路,即设置虚根再处理的做法:弄了一个上午,再次有种赶脚的感觉~~如果需要找出为什么需要去比所有权值之和更大的数为新增的虚边的话,一开始我理解仅 ...

  9. mysql cluster 名词概念解读

    Node Group [number_of_node_groups] = number_of_data_nodes / NoOfReplicas Partition When using ndbd, ...

  10. Django 1.6 最佳实践: 如何设置和使用 Log(转)

    原文: http://www.weiguda.com/blog/37/ 任何参与过高要求的大型项目的编程人员都明白设置适当的log等级, 创建不同的logger, 记录重要事件的重要性. 正确的设置和 ...