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

  智能指针(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. 百度地图API开发指南

    简介什么是百度地图API? 百度地图API是一套由JavaScript语言编写的应用程序接口,它能够帮助您在网站中构建功能丰富.交互性强的地图应用.百度地图API包含了构建地图基本功能的各种接口,提供 ...

  2. [转] C#操作Excel文件

    来自  jbp74c37ad170 的文章EXCEL编程语句有那些啊 全面控制 Excel首先创建 Excel 对象,使用ComObj:Dim ExcelID as Excel.Application ...

  3. [Everyday Mathematics]20150227

    (Marden's Theorem) 设 $p(z)$ 是三次复系数多项式, 其三个根 $z_1,z_2,z_3$ 不共线; 再设 $T$ 是以 $z_1,z_2,z_3$ 为顶点的三角形. 则存在唯 ...

  4. 【剑指offer 面试题38】数字在排序数组中出现的次数

    思路: 利用二分查找,分别查找待统计数字的头和尾的下标,最后做差加一即为结果. C++: #include <iostream> #include <vector> using ...

  5. oracle 查看表的相关信息

    1.查看当前用户的表 SELECT * FROM user_tables; 2.查看指定用户的表 SELECT * FROM all_tables WHERE owner = 'SYS';

  6. C++11 之 &quot; = delete &quot;

    1  缺省函数 设计一个类,没有成员函数 (member function),只有成员数据 (member data) class DataOnly { private: std::string st ...

  7. hadoop的kerberos认证

    言归正传,介绍过hadoop的simple认证和kerberos后,我们在这一章介绍hadoop的kerberos认证 我们还使用hadoop集群的机器. OS 版本: Centos6.4 Kerbe ...

  8. the NTP socket is in use, exiting

    centos下使用如下命令手动同步服务器时间 ntpdate ntp.fudan.edu.cn 或 ntpdate ntp.api.bz 出现“the NTP socket is in use, ex ...

  9. 分析fork后多进程对文件的共享

    fork函数是创建一个新的进程作为原进程的子进程,创建的子进程和父进程存在很多的相似性,首先父子进程的虚拟存储空间的用户空间是相同的,是将父进程的拷贝给子进程.同时父子进程对文件的操作是共享方式.因为 ...

  10. dom 左右两侧得广告(兼容IE FF)

    <!doctype html> <html> <head> <meta charset="utf-8"> <title> ...