1. 声明
#include <boost/shared_ptr.hpp>

class UsersBitmap {

...

}

typedef boost::shared_ptr<UsersBitmap> UsersBitmapPtr;

2. 使用

UsersBitmapPtr login_users_;
UsersBitmapPtr temp_login_users(new UsersBitmap());    //指向对象

login_users_.reset(new UsersBitmap());     //指针指向新的地方

login_users_.reset();  //指针置空

///

虽然boost.shared_ptr是个非常好的东西,使用它可以使得c++程序不需要考虑内存释放的问题,但是还是有很多必须注意的地方。下面罗列了一些本人在实际工作中经常碰到的使用shared_ptr出问题的几种情况。

1. shared_ptr多次引用同一数据,如下:
{
int* pInt = new int[100];
boost::shared_ptr<int> sp1(pInt);
// 一些其它代码之后…
boost::shared_ptr<int> sp2(pInt);
}

这种情况在实际中是很容易发生的,结果也是非常致命的,它会导致两次释放同一块内存,而破坏堆。

2.使用shared_ptr包装this指针带来的问题,如下:

class tester 
{
public:
  tester()
  ~tester()
  {
    std::cout << "析构函数被调用!\n"; 
  }
public:
  boost::shared_ptr<tester> sget()
  {
    return boost::shared_ptr<tester>(this);
  }
};

int main()
{
  tester t;
  boost::shared_ptr<tester> sp =  t.sget(); // …
  return 0;
}

也将导致两次释放t对象破坏堆栈,一次是出栈时析构,一次就是shared_ptr析构。若有这种需要,可以使用下面代码。

class tester : public boost::enable_shared_from_this<tester>
{
public:
  tester()
  ~tester()
  {
  std::cout << "析构函数被调用!\n"; 
  }
public:
  boost::shared_ptr<tester> sget()
  {
  return shared_from_this();
  }
};

int main()
{
  boost::shared_ptr<tester> sp(new tester);
  // 正确使用sp 指针。
  sp->sget();
  return 0;
}

3. shared_ptr循环引用导致内存泄露,代码如下:

class parent;
class child;

typedef boost::shared_ptr<parent> parent_ptr;
typedef boost::shared_ptr<child> child_ptr;

class parent
{
public:
       ~parent() { 
              std::cout <<"父类析构函数被调用.\n"; 
       }
public:
       child_ptr children;
};

class child
{
public:
       ~child() { 
              std::cout <<"子类析构函数被调用.\n"; 
       }
public:
       parent_ptr parent;
};

int main()
{
  parent_ptr father(new parent());
  child_ptr son(new child);
  // 父子互相引用。
  father->children = son;
  son->parent = father;
  return 0;
}

如上代码,将在程序退出前,father的引用计数为2,son的计数也为2,退出时,shared_ptr所作操作就是简单的将计数减1,如果为0则释放,显然,这个情况下,引用计数不为0,于是造成father和son所指向的内存得不到释放,导致内存泄露。

4. 在多线程程序中使用shared_ptr应注意的问题。代码如下:

class tester 
{
public:
  tester() {}
  ~tester() {}
  // 更多的函数定义…
};

void fun(boost::shared_ptr<tester> sp)
{
  // !!!在这大量使用sp指针.
  boost::shared_ptr<tester> tmp = sp;
}

int main()
{
  boost::shared_ptr<tester> sp1(new tester);
  // 开启两个线程,并将智能指针传入使用。
  boost::thread t1(boost::bind(&fun, sp1));
  boost::thread t2(boost::bind(&fun, sp1));
  t1.join();
  t2.join();
  return 0;
}

这个代码带来的问题很显然,由于多线程同是访问智能指针,并将其赋值到其它同类智能指针时,很可能发生两个线程同时在操作引用计数(但并不一定绝对发生),而导致计数失败或无效等情况,从而导致程序崩溃,如若不知根源,就无法查找这个bug,那就只能向上帝祈祷程序能正常运行。

可能一般情况下并不会写出上面这样的代码,但是下面这种代码与上面的代码同样,如下:

class tester 
{
public:
  tester() {}
  ~tester() {}
public:
  boost::shared_ptr<int> m_spData; // 可能其它类型。
};

tester gObject;

void fun(void)
{
  // !!!在这大量使用sp指针.
  boost::shared_ptr<int> tmp = gObject.m_spData;
}

int main()
{
  // 多线程。
  boost::thread t1(&fun);
  boost::thread t2(&fun);
  t1.join();
  t2.join();
  return 0;
}

情况是一样的。要解决这类问题的办法也很简单,使用boost.weak_ptr就可以很方便解决这个问题。第一种情况修改代码如下:

class tester 
{
public:
  tester() {}
  ~tester() {}
  // 更多的函数定义…
};

void fun(boost::weak_ptr<tester> wp)
{
  boost::shared_ptr<tester> sp = wp.lock;
  if (sp)
  {
    // 在这里可以安全的使用sp指针.
  }
  else
  {
    std::cout << “指针已被释放!” << std::endl;
  }
}

int main()
{
  boost::shared_ptr<tester> sp1(new tester);
  boost.weak_ptr<tester> wp(sp1);
  // 开启两个线程,并将智能指针传入使用。
  boost::thread t1(boost::bind(&fun, wp));
  boost::thread t2(boost::bind(&fun, wp));
  t1.join();
  t2.join();
  return 0;
}

boost.weak_ptr指针功能一点都不weak,weak_ptr是一种可构造、可赋值以不增加引用计数来管理shared_ptr的指针,它可以方便的转回到shared_ptr指针,使用weak_ptr.lock函数就可以得到一个shared_ptr的指针,如果该指针已经被其它地方释放,它则返回一个空的shared_ptr,也可以使用weak_ptr.expired()来判断一个指针是否被释放。

boost.weak_ptr不仅可以解决多线程访问带来的安全问题,而且还可以解决上面第三个问题循环引用。Children类代码修改如下,即可打破循环引用:

class child
{
public:
  ~child() { 
   std::cout <<"子类析构函数被调用.\n"; 
  }
public:
  boost::weak_ptr<parent> parent;
};

因为boost::weak_ptr不增加引用计数,所以可以在退出函数域时,正确的析构。

shared_ptr 的使用及注意事项相关推荐

  1. shared_ptr的一些尴尬

    http://blog.csdn.net/henan_lujun/article/details/8984543 shared_ptr在boost库中已经有多年了,C++11又为其正名,把他引入了ST ...

  2. 《Effective C++》 笔记

    文章目录 0.导读 命名习惯 1.让自己习惯C++ 条款01 条款02:尽量以const.enum.inline替换 #define 条款03:尽可能使用const 1.const与函数声明式关联 2 ...

  3. 智能指针shared_ptr的原理、用法和注意事项

    智能指针shared_ptr的原理.用法和注意事项 1 前言 2 shared_ptr原理 3 shared_ptr的基本用法 3.1 初始化 3.2 获取原始指针 4 智能指针和动态数组 4.1 c ...

  4. 【Smart_Point】C/C++ 中共享指针 shared_ptr

    1. 共享指针 shared_ptr 目录 1. 共享指针 shared_ptr 1.1 共享指针解决的问题? 1.2 创建 shared_ptr 对象 1.3 分离关联的原始指针 1.4 自定义删除 ...

  5. C++11中shared_ptr的使用

    在C++中,动态内存的管理是通过一对运算符来完成的:new,在动态内存中为对象分配空间并返回一个指向该对象的指针,可以选择对对象进行初始化:delete,接受一个动态对象的指针,销毁该对象,并释放与之 ...

  6. shared_ptr 用法

    引入 shared_ptr 是c++为了提高安全性而添加的智能指针,方便了内存管理. 特点 shared_ptr 是通过指针保持对象共享所有权的智能指针.多个 shared_ptr 对象可占有同一对象 ...

  7. 有关智能指针(shared_ptr)的讨论

    1. boost::shared_ptr的用法2. boost::shared_ptr的实现机制3. 使用boost::shared_ptr的注意事项4. std::tr1::shared_ptr和b ...

  8. c++ shared_ptr的使用

    shared_ptr.是c++为了提高指针安全性而添加的智能指针,方便了内存管理.功能非常强大,非常强大,非常强大(不单单是shared_ptr,配合week_ptr以及enable_share_fr ...

  9. [C++11]shared_ptr共享智能指针的初始化与使用

    使用智能指针需要添加头文件: 代码如下: #include <memory> shared_ptr使用的注意事项: 1.不能使用一个原始地址初始化多个共享智能指针 2.函数不能返回管理了t ...

最新文章

  1. push to origin/master was rejected错误解决方案(IDEA)
  2. ABP学习 解决:Update-Database : 无法将“Update-Database”项识别为 cmdlet、函数、脚本文件或可运行程序的名称的问题
  3. python可以干什么工作-python到底能做什么
  4. windows form (窗体) 之间传值
  5. 荣耀v40鸿蒙5g,荣耀V40pro再曝光,4K屏+双5000万+鸿蒙OS,再见了荣耀V30pro
  6. 微服务是否使SOA变得无关紧要?
  7. python实战系列之爬取CSDN博客之星2020年度排名情况(附源码)
  8. 号外号外!自动化测试工具AutoRunner V4.2 新版本升级预告!
  9. Nginx负载均衡策略介绍
  10. ts引入公共方法_angular 封装公共方法
  11. 两个工作流:什么时候选择BizTalk,什么时候选择WWF?微软人士给了一个简单的判断原则...
  12. handler回调主线程_Handler源码和9个常见问题的解答,这些你都掌握了吗?
  13. hg8245c backupsettings.html,如何通过中国电信光猫华为HG8245C打开IPV6
  14. U盘再次中毒——U盘文件消失却占内存
  15. 不懂中医的才攻击中医
  16. 爱心转发:宝贝,妈妈想死你了!你在哪里啊?(帮忙转一回吧)
  17. 一个简单的姓名拼音匹配
  18. mysql jdbc驱动 批量更新_jdbc-批量插入、批量删除、批量更新
  19. STM32移植LVGL8.0.2超详细的保姆级教程附移植好的工程文件
  20. 动态域名解析--每步动态域名解析

热门文章

  1. 不讲码德!坏味道偷袭我这个老码农
  2. 漫画:如何螺旋遍历二维数组?
  3. Debian下使用OpenLDAP 管理端
  4. 无法启动MySQL数据库
  5. .gitignore 无效及解决办法
  6. pip安装itchat模块成功后annocanda中No module named 'itchat'
  7. git常用命令速查表【转】
  8. Centos6.5安装Seafile,遇到的问题处理记录。
  9. /etc/issue、shutdown练习
  10. C# winform treeview node添加右键菜单并选中节点