Why Make_shared ?

C++11 中引入了智能指针, 同时还有一个模板函数 std::make_shared 可以返回一个指定类型的 std::shared_ptr, 那与 std::shared_ptr 的构造函数相比它能给我们带来什么好处呢 ?

优点

效率更高

shared_ptr 需要维护引用计数的信息,

  • 强引用, 用来记录当前有多少个存活的 shared_ptrs 正持有该对象. 共享的对象会在最后一个强引用离开的时候销毁( 也可能释放).
  • 弱引用, 用来记录当前有多少个正在观察该对象的 weak_ptrs. 当最后一个弱引用离开的时候, 共享的内部信息控制块会被销毁和释放 (共享的对象也会被释放, 如果还没有释放的话).

如果你通过使用原始的 new 表达式分配对象, 然后传递给 shared_ptr (也就是使用 shared_ptr 的构造函数) 的话, shared_ptr 的实现没有办法选择, 而只能单独的分配控制块:

1
2
auto p = new widget();
shared_ptr sp1{ p }, sp2{ sp1 };

如果选择使用 make_shared 的话, 情况就会变成下面这样:

1
auto sp1 = make_shared(), sp2{ sp1 };

内存分配的动作, 可以一次性完成. 这减少了内存分配的次数, 而内存分配是代价很高的操作.

关于两种方式的性能测试可以看这里 Experimenting with C++ std::make_shared

异常安全

看看下面的代码:

1
2
3
4
void F(const std::shared_ptr<Lhs>& lhs, const std::shared_ptr<Rhs>& rhs) { /* ... */ }

F(std::shared_ptr<Lhs>(new Lhs("foo")),
std::shared_ptr<Rhs>(new Rhs("bar")));

C++ 是不保证参数求值顺序, 以及内部表达式的求值顺序的, 所以可能的执行顺序如下:

  1. new Lhs(“foo”))
  2. new Rhs(“bar”))
  3. std::shared_ptr
  4. std::shared_ptr

好了, 现在我们假设在第 2 步的时候, 抛出了一个异常 (比如 out of memory, 总之, Rhs 的构造函数异常了), 那么第一步申请的 Lhs 对象内存泄露了. 这个问题的核心在于, shared_ptr 没有立即获得裸指针.

我们可以用如下方式来修复这个问题.

1
2
3
auto lhs = std::shared_ptr<Lhs>(new Lhs("foo"));
auto rhs = std::shared_ptr<Rhs>(new Rhs("bar"));
F(lhs, rhs);

当然, 推荐的做法是使用 std::make_shared 来代替:

1
F(std::make_shared<Lhs>("foo"), std::make_shared<Rhs>("bar"));

缺点

构造函数是保护或私有时,无法使用 make_shared

make_shared 虽好, 但也存在一些问题, 比如, 当我想要创建的对象没有公有的构造函数时, make_shared 就无法使用了, 当然我们可以使用一些小技巧来解决这个问题, 比如这里 How do I call ::std::make_shared on a class with only protected or private constructors?

对象的内存可能无法及时回收

make_shared 只分配一次内存, 这看起来很好. 减少了内存分配的开销. 问题来了, weak_ptr 会保持控制块(强引用, 以及弱引用的信息)的生命周期, 而因此连带着保持了对象分配的内存, 只有最后一个 weak_ptr 离开作用域时, 内存才会被释放. 原本强引用减为 0 时就可以释放的内存, 现在变为了强引用, 若引用都减为 0 时才能释放, 意外的延迟了内存释放的时间. 这对于内存要求高的场景来说, 是一个需要注意的问题. 关于这个问题可以看这里 make_shared, almost a silver bullet

参考

C++11使用make_shared的优势和劣势的更多相关文章

  1. Oracle RAC的五大优势及其劣势

    Oracle RAC的五大优势及其劣势 不同的集群产品都有自己的特点,RAC的特点包括如下几点: 双机并行.RAC是一种并行模式,并不是传统的主备模式.也就是说,RAC集群的所有成员都可以同时接收客户 ...

  2. Mono for Android 优势与劣势

    原文:Mono for Android 优势与劣势 最近有兴趣了解一下Mono for Andriod,也就是使用.NET平台来开发Andriod程序.Mono for Android API 几乎映 ...

  3. 17.1.2.1 Advantages and Disadvantages of Statement-Based and Row-Based Replication 基于语句和行的复制的优势和劣势

    17.1.2.1 Advantages and Disadvantages of Statement-Based and Row-Based Replication 基于语句和行的复制的优势和劣势 每 ...

  4. (转)Mono for Android 优势与劣势

    最近有兴趣了解一下Mono for Andriod,也就是使用.NET平台来开发Andriod程序.Mono for Android API 几乎映射标准的Andriod API.例如,两边API几乎 ...

  5. JSP的优势与劣势浅析

    本文简单介绍了JSP技术,并对JSP的优势与劣势进行了简单的分析.JSP页面由HTML代码和嵌入其中的Java代码所组成. JSP(JavaServer Pages)是由Sun Microsystem ...

  6. NanShan即时通讯论——HTML5的优势与劣势

    原文:NanShan即时通讯论--HTML5的优势与劣势 NanShan即时通讯 学习html时才是XHTML 1.0,接着是 HTML4.01,再到HTML5,如今HTML5 開始吸引越来越多的人的 ...

  7. 『Asp.Net 组件』Asp.Net 服务器组件 的开发优势和劣势

    在写<Asp.Net 服务器组件系列文档>之前,笔者不才,揣测微软战略用意: 微软利益诉求莫过于 微软产品和技术的市场份额: 因此,微软战略之一莫过于将 所有开发人员 团聚在 微软周围,以 ...

  8. [转] iOS 动画库 Pop 和 Canvas 各自的优势和劣势是什么?

    iOS 动画库 Pop 和 Canvas 各自的优势和劣势是什么? http://www.zhihu.com/question/23654895/answer/25541037 拿 Canvas 来和 ...

  9. JSP的优势 和劣势 与php的比较

    一 jsp的 优势 与劣势 由于JSP页面的内置脚本语言是基于Java编程语言的,而且所有的JSP页面都被编译成为Java Servlet,JSP页面就具有Java技术的所有好处,包括健壮的存储管理和 ...

随机推荐

  1. Microsoft Onenote shortcuts / Onenote快捷键大全

    Onenote跟Libreoffice ,有道笔记比起来一个快捷键特别不太好用,就是Ctrl + Shift +v 并不会提供一个选择粘贴模式选项. 而在Onenote 中 Ctrl + Shift ...

  2. java 懒汉式、饿汉式单例模式 不含多线程的情况

    //饿汉式 提前生成了单例对象 class Singleton{ private static final Singleton instance=new Singleton(); private Si ...

  3. Spring源码窥探之:ImportSelector

    1. 编写实现ImportSelector的类 /** * @author 70KG * @Title: SelectImportBean * @Description: * @date 2018/7 ...

  4. HDFS节点及原理

    HDFS节点角色: (1)namenode:1.用来存储HDFS的元数据信息,这里的元数据信息指的是文件系统的命名空间.启动时,将这些信息加载到namenode内存. 2.元数据信息也会在磁盘上保存成 ...

  5. CF19D Points 平衡树

    题意:支持插入/删除点 $(x,y)$,查询一个点右上方横坐标与之最接近的点坐标. 我们可以对于每一个操作过的横坐标都开一个 $set$,然后再开一个平衡树,维护每个横坐标上最大的纵坐标. 然后查询点 ...

  6. cgp的辣鸡比赛题解

    目录 cgp的gcd 题目链接 思路 代码 cgp调戏妹子 题目链接 思路 代码 cgp的序列 题目链接 思路 代码 cgp的背包 题目链接 思路 代码 cgp的gcd 题目链接 传送门 思路 首先看 ...

  7. Processing 2.1.1 无法使用video和movie问题解决方案

    升级到2.1.1后,尝试着运行了一下sample中的video和movie,结果都报错,上网搜了一下,找到解决方法. 1. 首先来看movie的错误,如下: JNA: Callback org.gst ...

  8. AtCoder Grand Contest 015题解

    传送门 \(A\) 找到能达到的最大的和最小的,那么中间任意一个都可以被表示出来 typedef long long ll; int n,a,b;ll res; int main(){ scanf(& ...

  9. cometoj---contest#3 棋盘

    棋盘:(状压dp) 传送门:https://www.cometoj.com/contest/38/problem/B?problem_id=1535 题目描述 小猫有一个 2×N 的棋盘,每一个格子放 ...

  10. SqrtTree学习笔记

    散步的时候yy区间最值的不同分块做法,发现单点修改\(O(\sqrt{n})\)查询\(O(1)\)的做法不是很会? 于是yy了一个奇怪做法,写出来看看. 考虑查询的时候两端的散点可以用前后缀最值查出 ...