shared_ptr

std::shared_ptr<int> sp1 = new int();  // shared count = 1, weak count = 0
std::shared_ptr<int> sp2(sp1); // shared count = 2, weak count = 0
std::shared_ptr<int> sp3 = sp2; // shared count = 3, weak count = 0 std::weak_ptr<int> wp1(sp1); // shared count = 3, weak count = 1
std::weak_ptr<int> wp2(wp1); // shared count = 3, weak count = 2
std::weak_ptr<int> wp3 = wp2; // shared count = 3, weak count = 3

shared_ptr weak_ptr 使用 reset 或者指向另一个 managed object导致 shared count或weak count相应的减一。

  1. 类继承中使用shared_ptr
class Base {};
class Derived : public Base {};
......
shared_ptr<Derived> dp1(new Derived);
shared_ptr<Base> bp1 = dp1;
shared_ptr<Base> bp2(dp1);
shared_ptr<Base> bp3(new Derived);
  1. casting shared_ptr
shared_ptr<Base> base_ptr (new Base);
shared_ptr<Derived> derived_ptr;
// if static_cast<Derived *>(base_ptr.get()) is valid, then the following is valid:
derived_ptr = static_pointer_cast<Derived>(base_ptr);
  1. make_shared

使用shared_ptr = new int(),会导致两次内存分配:int对象的内存分配跟shared_ptr内部的 manager object 一次内存分配。make_shared 对此进行了优化,一次性分配 int + manager object 内存空间大小。

make_shared 用法:

shared_ptr<Thing> p (make_shared<Thing>(42, "I'm a Thing!"));
shared_ptr<Base> bp(make_shared<Derived1>()); // shared_ptr中的 template参数与make_shared中的tmeplate参数可以不一样(继承关系)

使用 weak_ptr

void do_it(weak_ptr<Thing> wp){
shared_ptr<Thing> sp = wp.lock(); // get shared_ptr from weak_ptr
if(sp)
sp->defrangulate(); // tell the Thing to do something
else
cout << "The Thing is gone!" << endl;
}

也可以直接从weak_ptr构建shared_ptr,这个时间如果weak_ptr过期(通过 weak_ptr::expired() 可以查询),则抛出异常:

void do_it(weak_ptr<Thing> wp){
shared_ptr<Thing> sp(wp); // construct shared_ptr from weak_ptr
// exception thrown if wp is expired, so if here, sp is good to go
sp->defrangulate(); // tell the Thing to do something
}

shared_ptr 线程安全

shared_ptr / weak_ptr 中的引用计数是线程安全的(atomic/memory barrier);但是跨线程赋值操作、reset操作没有线程安全。即

  1. shared_ptr 仅保证引用计数的正确性,在引用计数减为0之后,析构掉被管理对象;
  2. 在当前线程中进行赋值操作。不应在其他线程中进行赋值、reset操作;

enable_shared_from_this 及 shared_from_this

定义一个类,实现内存自动管理。两次调用 get 返回的是两个不同的shared_ptr,将导致同一个BadThing对象两次析构。

class BadThing {
public:
BadThing() = default;
shared_ptr<BadThing> get() { return std::make_shared<BadThing>(); }
};
  1. enable_shared_from_this的实现
// enable_shared_from_this的实现
// 基于(/usr/include/c++/7.3.0/bits/shared_ptr.h)
// 此代码是对gcc实现的简化版本, 仅作为描述原理用.
template<typename T>
class enable_shared_from_this
{
public:
shared_ptr<T> shared_from_this()
{
return shared_ptr<T>(this->weak_this);
}
shared_ptr<const T> shared_from_this() const
{
return shared_ptr<const T>(this->weak_this);
}
private:
template<typename>
friend class shared_ptr; template<typename T1>
void _M_weak_assign(T1* p, const shared_count<>& n)
{
  weak_this._M_assign(p, n);
} mutable weak_ptr<T> weak_this;
};

enable_shared_from_this 类中定义了一个 weak_ptr, 起到了上文提到的从obj指针生成 shared_ptr 对象的作用. 按照先前的原理, 我们可能认为是在obj初始化的时候, 同时对 weak_this 进行初始化, 但是在这段代码里显然没有对 weak_this 进行任何初始化工作(原始代码里也没有, gcc为什么不这样实现呢? 这是因为当对象没有由智能指针管理时, 这些操作是没有必要的. 所以应该把这个任务交给 shared_ptr). 第一个持有 Good 对象 g_obj 的 shared_ptr sp1 会对 g_obj 的 weak_this 进行处理, 使其有效. 具体见参考。

为什么

  1. 为什么需要 weak_ptr:编译期间解除A/B循环引用导致两者都不能释放内存,使用weak_ptr作为对方的引用 ref
  2. 为什么需要 enable_shared_from_this:特别的,在类内部需要调用函数(如创建线程等异步处理将自身作为参数);

参考

Using C++11’s Smart Pointers PDF

enable_shared_from_this类的作用和实现

std::shared_ptr std::weak_ptr 线程安全性

从 shared_from_this() 谈智能指针 weak_ptr 和 shared_ptr 的实现

(C++) C++ 中 shared_ptr weak_ptr的更多相关文章

  1. stl中auto_ptr,unique_ptr,shared_ptr,weak_ptr四种智能指针使用总结

    stl中auto_ptr,unique_ptr,shared_ptr,weak_ptr四种智能指针使用总结 1. auto_ptrauto_ptr主要是用来解决资源自动释放的问题,比如如下代码:voi ...

  2. shared_ptr & weak_ptr

    shared_ptr <1> 类模板说明 namespace boost { class bad_weak_ptr: public std::exception; template< ...

  3. C++ 智能指针(shared_ptr/weak_ptr)原理分析

    其主要的类关系如下所示(省略相关的类模板参数): 图1 从上面的类图可以清楚的看出shared_ptr内部含有一个指向被管理对象(managed object)T的指针以及一个__shared_cou ...

  4. shared_ptr / weak_ptr 代码片段

    参考<<Boost程序库完全开放指南>> shared_ptr  类摘要(只列出了常用的部分)和相关说明 template <class T> class shar ...

  5. boost shared_ptr weak_ptr

    文档: http://www.boost.org/doc/libs/1_57_0/libs/smart_ptr/shared_ptr.htm shared_ptr构造有个原型 template< ...

  6. auto_ptr,unique_ptr,shared_ptr,weak_ptr

    http://mojijs.com/2016/08/218129/index.html http://www.cnblogs.com/lanxuezaipiao/p/4132096.html

  7. C++ 标准库智能指针

    整理一下c++中shared_ptr,weak_ptr,unique_ptr三种指针的使用案例和注意事项,让程序资源更加案例,在标准库中,需要包含<memory>,在boost库中, 一. ...

  8. 关于shared_ptr与weak_ptr的使用(good)

    shared_ptr是带引用计数的智能指针,可以说大部分的情形选择用shared_ptr不会出问题.那么weak_ptr是什么,应该怎么用呢? weak_ptr也是智能指针,但是比较弱,感觉没什么用. ...

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

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

  10. shared_ptr&scoped_ptr&weak_ptr

    [RAII - Resource Acquisition Is Initialization] 获得一个资源的时候,不管这个资源是对象.内存.文件句柄或者其它什么,你都要在一个对象的构造函数中获得它, ...

随机推荐

  1. this的指向问题、bind/call/apply改变this指向

    this的指向问题 全局作用域下的this指向 无论是否是严格模式,全局作用域下的this始终指向window 函数内部的this 严格模式下: function test() { 'use stri ...

  2. Mysql 安全加固经验总结

    本文为博主原创,转载请注明出处: 目录 1.内网部署Mysql 2. 使用独立用户运行msyql 3.为不同业务创建不同的用户,并设置不同的密钥 4.指定mysql可访问用户ip和权限 5. 防sql ...

  3. Nginx相关模块学习使用实践指南

    转载自:https://www.bilibili.com/read/cv16150654?spm_id_from=333.999.0.0 0x01 Nginx 常用模块使用实践 官方模块使用手册:ht ...

  4. 使用 Elastic 技术栈构建 K8S 全栈监控 -2: 用 Metricbeat 对 Kubernetes 集群进行监控

    文章转载自:https://www.qikqiak.com/post/k8s-monitor-use-elastic-stack-2/ 操作步骤 git clone https://github.co ...

  5. 6.Ceph 基础篇 - CephFS 文件系统

    文章转载自:https://mp.weixin.qq.com/s?__biz=MzI1MDgwNzQ1MQ==&mid=2247485294&idx=1&sn=e9039504 ...

  6. Redis从入门到高级笔记【涵盖重点面试题】

    NoSQL数据库 DBEngines网站中会统计目前数据库在全世界的排名 1.1 什么是NoSQL 最常见的解释是"non-relational",很多人说它是"Not ...

  7. MongoDB 单实例节点主机的用户和权限一般操作步骤

    步骤总结: 1.先正常启动 2.创建用户,创建数据库病授权用户 3.关闭程序,开启安全,然后启动 4.使用账号和密码连接 按未开启认证的方式(配置文件中没开启安全选项并且启动命令中不添加 --auth ...

  8. 如何评判一个企业是否需要实施erp系统?

    一个企业是否需要实施ERP系统很大程度上取决于其规模.这里需要向提问者说明的一点是:很多企业上ERP,并不会用得到MRP,ERP是企业资源计划,不是制造业企业专用,MRP也不是ERP必须,金融.保险之 ...

  9. 220722 T3 石子染色 (背包)

    序列s中的数就是要选的堆的编号,假设要选的有i个石子,这i个染为红色,剩下j个染为蓝色,i+j=x,i=x-j,那么对答案的贡献是|x-2j|.那么只要我们选的有i个石子,贡献就是这么多,所以我们可以 ...

  10. 洛谷U81904 【模板】树的直径

    有负边权,所以用树形DP来找树的直径. 1 //树形DP求树的直径 2 #include<bits/stdc++.h> 3 using namespace std; 4 const int ...