智能指针机制跟Objective-C里面的retainCount引用计数有着相同的原理,当某个对象的引用计数为0是执行delete操作,类似于autorelease

初学者在使用智能指针时,很多情况下可以把它当做标准C++中的T*来理解。比如:

  1. typedef boost::shared_ptr<CMyLargeClass> CMyLargeClassPtr;
  2.  
  3. std::vector<CMyLargeClassPtr> vec;
  4.  
  5. vec.push_back( CMyLargeClassPtr(new CMyLargeClass("bigString")) );

这里的CMyLargeClassPtr可以用CMyLargeClass *来理解,但是在使用上还是有一些区别的,请看下面:

先看一个例子:

许多容器类,包括STL,都需要拷贝操作(例如,我们插入一个存在的元素到list,vector,或者container。)当拷贝操作是非常销毁资源的时候(这些操作时必须的),典型的操作就是使用容器指针。

std::vector<CMyLargeClass *> vec;

vec.push_back( new CMyLargeClass("bigString") );

将内存管理的任务抛给调用者,我们能够使用shared_ptr来实现。

typedef boost::shared_ptr<CMyLargeClass>  CMyLargeClassPtr;

std::vector<CMyLargeClassPtr> vec;

vec.push_back( CMyLargeClassPtr(new CMyLargeClass("bigString")) );

使用智能指针的一些操作会产生错误(突出的事那些不可用的引用计数器,一些对象太容易释放,或者根本释放不掉)。Boost增强了这种安全性,处理了所有潜在存在的危险,所以我们要遵循以下几条规则使我们的代码更加安全。

下面几条规则是你应该必须遵守的:

规则一:赋值和保存 —— 对于智能指针来说,赋值是立即创建一个实例,并且保存在那里。现在智能指针拥有一个对象,你不能手动释放它,或者取走它,这将帮助你避免意外地释放了一个对象,但你还在引用它,或者结束一个不可用的引用计数器。

规则二:_ptr<T> 不是T* —— 恰当地说,不能盲目地将一个T* 和一个智能指针类型T相互转换。意思是:

·         当创建一个智能指针的时候需要明确写出 __ptr<T> myPtr(new T)。

·         不能将T*赋值给一个智能指针。

·         不能写ptr = NULL,应该使用ptr.reset()。

·         重新找回原始指针,使用ptr.get(),不必释放这个指针,智能指针会去释放、重置、赋值。使用get()仅仅通过函数指针来获取原始指针。

·         不能通过T*指向函数指针来代表一个__ptr<T>,需要明确构造一个智能指针,或者说将一个原始指针的所有权给一个指针指针。(见规则三)

·         这是一种特殊的方法来认定这个智能指针拥有的原始指针。不过在Boost:smart pointer programming techniques 举例说明了许多通用的情况。

规则三:非循环引用 —— 如果有两个对象引用,而他们彼此都通过一个一个引用指针计数器,那么它们不能释放,Boost 提供了weak_ptr来打破这种循环引用(下面介绍)。

规则四:非临时的 share_ptr —— 不能够造一个临时的share_ptr来指向它们的函数,应该命名一个局部变量来实现。(这可以使处理以外更安全,Boost share_ptr best practices 有详细解说)。

7、 循环引用

引用计数器是一种便利的资源管理机制,它有一个基本回收机制。但循环引用不能够自动回收,计算机很难检测到。一个最简单的例子,如下:

struct CDad;

struct CChild;

typedef boost::shared_ptr<CDad>   CDadPtr;

typedef boost::shared_ptr<CChild>  CChildPtr;

struct CDad : public CSample

{

CChildPtr myBoy;

};

struct CChild : public CSample

{

CDadPtr myDad;

};

// a "thing" that holds a smart pointer to another "thing":

CDadPtr   parent(new CDadPtr);

CChildPtr child(new CChildPtr);

// deliberately create a circular reference:

parent->myBoy = child;

child->myDad = dad;

// resetting one ptr...

child.reset();

parent 仍然引用CDad对象,它自己本身又引用CChild。整个情况如下图所示:

如果我们调用dad.reset(),那么我们两个对象都会失去联系。但这种正确的离开这个引用,共享的指针看上去没有理由去释放那两个对象,我们不能够再访问那两个对象,但那两个对象的确还存在,这是一种非常严重的内存泄露。如果拥有更多的这种对象,那么将由更多的临界资源不能正常释放。

如果不能解决好共享智能指针的这种操作,这将是一个严重的问题(至少是我们不可接受的)。因此我们需要打破这种循环引用,下面有三种方法:

A、   当只剩下最后一个引用的时候需要手动打破循环引用释放对象。

B、   当Dad的生存期超过Child的生存期的时候,Child需要一个普通指针指向Dad。

C、  使用boost::weak_ptr打破这种循环引用。

方法A和B并不是一个完美的解决方案,但是可以在不使用weak_ptr的情况下让我们使用智能指针

============================================================

更多详细内容请看博客http://blog.csdn.net/dongguan131/article/details/6683843

与shared_ptr相类似的是scoped_ptr、auto_ptr。boost::scoped_ptr和std::auto_ptr非常类似,是一个简单的智能指针,二者都能够保证在离开作用域后对象被释放。

  1. #include <string>
  2. #include <iostream>
  3. #include <boost/scoped_ptr.hpp>
  4.  
  5. class implementation
  6. {
  7. public:
  8. ~implementation() { std::cout <<"destroying implementation\n"; }
  9. void do_something() { std::cout << "did something\n"; }
  10. };
  11.  
  12. void test()
  13. {
  14. boost::scoped_ptr<implementation> impl(new implementation());
  15. impl->do_something();
  16. }
  17.  
  18. void main()
  19. {
  20. std::cout<<"Test Begin ... \n";
  21. test();
  22. std::cout<<"Test End.\n";
  23. }

Scoped_ptr

该代码的输出结果是:

Test Begin ...
did something
destroying implementation
Test End.

可以看到:当implementation类离其开impl作用域的时候,会被自动删除,这样就会避免由于忘记手动调用delete而造成内存泄漏了。

boost::scoped_ptr的实现和std::auto_ptr非常类似,都是利用了一个栈上的对象去管理一个堆上的对象,从而使得堆上的对象随着栈上的对象销毁时自动删除。不同的是,boost::scoped_ptr有着更严格的使用限制——不能拷贝。这就意味着:boost::scoped_ptr指针是不能转换其所有权的。

    1. 不能转换所有权
      boost::scoped_ptr所管理的对象生命周期仅仅局限于一个区间(该指针所在的"{}"之间),无法传到区间之外,这就意味着boost::scoped_ptr对象是不能作为函数的返回值的(std::auto_ptr可以)。
    2. 不能共享所有权
      这点和std::auto_ptr类似。这个特点一方面使得该指针简单易用。另一方面也造成了功能的薄弱——不能用于stl的容器中。
    3. 不能用于管理数组对象
      由于boost::scoped_ptr是通过delete来删除所管理对象的,而数组对象必须通过deletep[]来删除,因此boost::scoped_ptr是不能管理数组对象的,如果要管理数组对象需要使用boost::scoped_array类。

【原/转】【boost】智能指针使用规则以及介绍的更多相关文章

  1. 基于C/S架构的3D对战网络游戏C++框架 _05搭建系统开发环境与Boost智能指针、内存池初步了解

    本系列博客主要是以对战游戏为背景介绍3D对战网络游戏常用的开发技术以及C++高级编程技巧,有了这些知识,就可以开发出中小型游戏项目或3D工业仿真项目. 笔者将分为以下三个部分向大家介绍(每日更新): ...

  2. Boost智能指针-基础知识

    简单介绍 内存管理一直是 C++ 一个比較繁琐的问题,而智能指针却能够非常好的解决问题,在初始化时就已经预定了删除.排解了后顾之忧.1998年修订的第一版C++标准仅仅提供了一种智能指针:std::a ...

  3. [转] Boost智能指针——scoped_ptr

    http://www.cnblogs.com/tianfang/archive/2008/09/15/1291050.html boost::scoped_ptr和std::auto_ptr非常类似, ...

  4. boost 智能指针intrusive_ptr

    boost::intrusive_ptr一种“侵入式”的引用计数指针,它实际并不提供引用计数功能,而是要求被存储的对象自己实现引用计数功能,并提供intrusive_ptr_add_ref和intru ...

  5. Boost智能指针使用总结

    内存管理是一个比较繁琐的问题,C++中有两个实现方案: 垃圾回收机制和智能指针.垃圾回收机制因为性能等原因不被C++的大佬们推崇, 而智能指针被认为是解决C++内存问题的最优方案. 1. 智能指针定义 ...

  6. Boost智能指针——weak_ptr

    循环引用: 引用计数是一种便利的内存管理机制,但它有一个很大的缺点,那就是不能管理循环引用的对象.一个简单的例子如下: #include <string>#include <iost ...

  7. boost智能指针总结

    智能指针是一种具备指针类似行为的对象,当不在需要它的时候自动删除其引用的c++对象.直接点说就是自动析构C++对象. boost提供了6种智能指针,如下所示: scoped_ptr <boost ...

  8. Boost智能指针——scoped_ptr

    boost::scoped_ptr和std::auto_ptr非常类似,是一个简单的智能指针,它能够保证在离开作用域后对象被自动释放. 上一段代码,以及其输出: #include <string ...

  9. [原][C++]拒绝智能指针与指针混用,常见智能指针问题

    公司一个非专科的程序在开发过程中有些毛躁,但是又想使用些新学的技术 这天他正调试呢,发现有一个BUG怎么也找不到原因. 用的好好的内存怎么就突然被删除了呢,好好的指针,怎么就访问越界了呢 没办法,他只 ...

随机推荐

  1. AssetBundle系列——打包前进行平台检测

    在生成AssetBundle的时候,如果目标平台和当前平台不一致,Unity3D会自动将当前平台转换为目标平台. 如果项目中资源量比较大,这个转换过程是相当漫长的,并且不能够强行中止. 所以最好在Bu ...

  2. IIS6.0启动网站ManagedPipelineHandler异常

    处理程序“PageHandlerFactory-Integrated”在其模块列表中有一个错误模块“ManagedPipelineHandler” 开发web项目需要安装IIS,当安装完以后,web程 ...

  3. 疯狂的ASP.NET系列-第一篇:啥是ASP.NET

    最近想学下ASP.NET,于是在网店上看到一本书叫做ASP.NET高级程序设计,老婆在旁边问了句:“这个不是DSP(数字信号处理,大学读的电子,所以这个比较熟),是ASP啊,什么是ASP啊?”.我想了 ...

  4. 【转载】解决 Subversion 的 “svn: Can't convert string from 'UTF-8' to native encoding” 错误

    转载自:http://blog.csdn.net/shaohui/article/details/3996274 在google code 上创建了一个新的项目, 用Windows 下面的tortoi ...

  5. Pattern Lab - 构建先进的原子设计系统

    Pattern Lab 是一个工具集,帮助您创建原子设计系统.在它的核心,是一个自定义静态网站生成器,构建了类似原子,分子和界面结合在一起,形成模板和页面.Pattern Lab 可以作为项目的模式库 ...

  6. js-数据类型

    js中有5种数据类型:Undefined.Null.Boolean.Number和String.还有一种复杂的数据类型Object,Object本质是一组无序的名值对组成的. 一.数据类型 1.und ...

  7. sqlite3存储格式

    本篇介绍sqlite3数据库文件的存储格式.通过阅读源读源代码可以知道sqlite的设计思想.一个sqlite数据库文件对应着一个数据库.sqlite将数据库文件划分大小一致的存储(以区分内存)页面, ...

  8. 在VS中使用TinyFox调试OWIN应用(转)

    在很早一段时间之前,我曾经写过一篇关于Katana的使用方法的文章<如何安装并简单的使用OwinHost——Katana>,上面就有介绍如何在VS中调试使用Katana作为Host的App ...

  9. 用cryptico.js实现RSA加密(应对cryptico不支持PEM)

    问题: 随手分享一下好了,这个问题困扰了很久. cryptico.js这个加密算法库很全,很适合在前端用到各种加密解密算法的需求.但是美中不足的是,它的RSA加密不支持PEM格式,所以如果你后端用ja ...

  10. sprint3与总结

    backlog-看板-燃尽图-每日立会 github:https://github.com/alfredzhu/team-work 总结:这种团队合作的方式很好,大家在一起沟通,相互交流想法,一起解决 ...