mhcoderwl

自顶向下探索世界,自底向上改变世界 -----WL

  • 主页
  • 标签
所有文章 友链 关于我

mhcoderwl

自顶向下探索世界,自底向上改变世界 -----WL

  • 主页
  • 标签

shared_ptr和weak_ptr

2017-09-22

shared_ptr

线程安全性

shared_ptr 本身不是 100% 线程安全的。它的引用计数本身是安全且无锁的,但对象的读写则不是,因为 shared_ptr 有两个数据成员,读写操作不能原子化。根据文档,shared_ptr 的线程安全级别和内建类型、标准库容器、string 一样,即:

  • 一个 shared_ptr 实体可被多个线程同时读取;
  • 两个的 shared_ptr 实体可以被两个线程同时写入,“析构”算写操作;
  • 要从多个线程读写同一个 shared_ptr 对象,那么需要加锁。

    用法

    1
    2
    3
    4
    5
    6
    7
    8
    shared_ptr<int> sp(new int(10)); //一个指向整数的shared_ptr
    assert(sp.unique()); //现在shared_ptr是指针的唯一持有者
    shared_ptr<int> sp2 = sp; //第二个shared_ptr,拷贝构造函数
    assert(sp == sp2 && sp.use_count() == 2); //两个shared_ptr相等,指向同一个对象,引用计数为2
    *sp2 = 100; //使用解引用操作符修改被指对象
    assert(*sp == 100); //另一个shared_ptr也同时被修改
    sp.reset(); //停止shared_ptr的使用
    assert(!sp); //sp不再持有任何指针(空指针)

提示:shared_ptr可作为容器的元素,重载了比较和拷贝操作符,auto_ptr不可以

使用陷阱

意外延长声明周期

shared_ptr是强引用,只要有一个指向对象的shared_ptr存在,该对象就不会析构.
要注意bind函数,bind会把实参拷贝一份,意外延长对象生命周期

函数参数

我们用const引用来传递类型为shared_ptr的函数参数

析构所在的线程

对象的析构是同步的,当最后一个指向x的shared_ptr离开其作用域的时候,x会同时在同一个线程析构,这个线程不一定是对象诞生的线程,如果析构比较耗时,并且在关键线程中析构,那么会拖累线程的速度,
解决办法是我们可以单独开一个线程专门用来析构,通过一个BlockingQueue >把对象的析构都转移到那个专用线程,从而解放关键线程.
注:shared_ptr 可以持有任何对象

weak_ptr

weak_ptr是为了配合shared_ptr而引入的一种智能指针,它更像是shared_ptr的一个助手而不是智能指针,因为它不具有普通指针的行为,没有重载operator*和->,它的最大作用在于协助shared_ptr工作,像旁观者那样观测资源的使用情况.
用法:

  • weak_ptr被设计为与shared_ptr共同工作,可以从一个shared_ptr或者另一个weak_ptr对象构造,获得资源的观测权。但weak_ptr没有共享资源,它的构造不会引起指针引用计数的增加。
  • 使用weak_ptr的成员函数use_count()可以观测资源的引用计数,另一个成员函数expired()的功能等价于use_count()==0,但更快,表示被观测的资源(也就是shared_ptr的管理的资源)已经不复存在。
  • weak_ptr可以使用一个非常重要的成员函数lock()从被观测的shared_ptr获得一个可用的shared_ptr对象, 从而操作资源。但当expired()==true的时候,lock()函数将返回一个存储空指针的shared_ptr.

获得this的shared_ptr

weak_ptr的一个重要用途是获得this指针的shared_ptr,使对象自己能够生产shared_ptr管理自己:对象使用weak_ptr观测this指针,这并不影响引用计数,在需要的时候就调用lock()函数,返回一个符合要求的shared_ptr使外界使用。

这个解决方案被实现为一个惯用法,在头文件定义了一个助手类enable_shared_from_this,其声明如下:

1
2
3
4
5
6
7
template<class T>
class enable_shared_from_this
{
public:
shared_ptr<T> shared_from_this();
}

使用的时候只需要让想被shared_ptr管理的类从它继承即可,成员函数shared_from_this()会返回this的shared_ptr

使用示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
#include <boost/smart_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/make_shared.hpp>
using namespace boost;
using namespace std;
class self_shared:
public enable_shared_from_this<self_shared>{
public:
self_shared(int n):x(n){}
int x;
void print(){
cout << "self_shared:" << x << endl;
}
};
int main(){
shared_ptr<self_shared> sp =
make_shared<self_shared>(315);
sp->print();
shared_ptr<self_shared> p = sp->shared_from_this();
p->x = 100;
p->print();
}

weak_ptr还有个用处就是解决循环引用造成的内存泄漏,举个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class A{
public:
~A(){
}
shared_ptr<B> b;
};
class B{
public:
~B(){
}
shared_ptr<A> a;
};
int main(){
shared_ptr<A> test1=new A;
shared_ptr<B> test2=new B;
test1->b=test2;
test2->a=test1;
return 0;
}

由于A释放时引用计数大于1,所以不析构,导致B释放时引用计数也大于1,也不析构,造成内存泄漏,解决办法是将一方改成weak_ptr,但是必须要程序员意识到这里会出现循环引用.

赏

谢谢你请我吃糖果

  • c++
  • stl

扫一扫,分享到微信

微信分享二维码
服务器开发测试常用命令和工具
服务器项目关键组件
© 2018 mhcoderwl
Hexo Theme Yilia by Litten
  • 所有文章
  • 友链
  • 关于我

tag:

  • unp
  • unix
  • socket
  • JAVASE
  • apue
  • muduo
  • c++
  • stl
  • c/c++
  • 编译器
  • C--
  • c
  • FakeCC
  • python
  • sql
  • web 开发
  • Flask框架
  • 算法
  • 面试
  • linux
  • 教程
  • hexo
  • 博客
  • sockets
  • 服务器

    缺失模块。
    1、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    2、在根目录_config.yml里添加配置:

      jsonContent:
        meta: false
        pages: false
        posts:
          title: true
          date: true
          path: true
          text: true
          raw: false
          content: false
          slug: false
          updated: false
          comments: false
          link: false
          permalink: false
          excerpt: false
          categories: false
          tags: true
    

  • 昊师兄的博客
目前在东南大学读研
擅长c/c++,linux,shellscript
做一些3D人脸识别的研究
有兴趣一起交流学习!