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. 【Low版】HAUT - OJ - Contest1035 - 2017届新生周赛(六)题解

    问题 A: 比赛 时间限制: 2 秒 内存限制: 256 MB | 提交: 393 解决: 98提交 状态 题目描述 学校要派6名同学组成两个队(一个队3个人)去参加比赛,每个同学有一个分数,学校希望 ...

  2. window下关闭占用端口使用

    怎么在window下关闭端口! 1:查看特定端口被占用情况 命令:   netstat -ano 和 netstat -ano|findstr 端口号 netstat -ano:查看电脑所有端口被占用 ...

  3. vue slot 插槽详解

    插槽含义:就是引入子组件后,在插入子组件元素中添加信息或者标签,使得子组件的指定位置插入信息或者标签 插槽有三种:默认插槽.具名插槽.作用域插槽,由于vue2.6.0后对插槽进行修改,但是兼容2.6. ...

  4. mysql 两张表字段模糊匹配--字符串拼接函数

    concat(A,B,C,...)  拼接字符串 例如concat('123','***','345')  =>123***345 SELECT concat( substr(t1.CODE, ...

  5. grep命令的or,and,not操作的例子

    在Linux的grep命令中如何使用OR,AND,NOT操作符呢? 其实,在grep命令中,有OR和NOT操作符的等价选项,但是并没有grep AND这种操作符.不过呢,可以使用patterns来模拟 ...

  6. PPT扁平化设计总结

    注:以下内容基本都来自知乎,由于已经不记得网址了,所以未能附上所有相关链接,抱歉. PPT扁平化设计原则一.亲密:意思相近的内容放在一起二.对齐:页面上的某两个元素之间总是围绕一条直线对齐三.对比:有 ...

  7. linux学习5 Linux开篇入门和基本操作

    一.完整的操作系统 1.GNU系统:表示GNU is Not Unix.表示不做商业化.制定了GPL(General Public License)即任何软件程序只要遵循GPL协议就是自由软件.还制定 ...

  8. Linux中三种SCSI target的介绍之SCST

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/scaleqiao/article/deta ...

  9. 复习题之Blah数集

    题目描述: 大数学家高斯小时候偶然间发现一种有趣的自然数集合Blah,对于已a为基的集合Ba定义如下: (1)a是集合Ba的基,且a是Ba的第一个元素: (2)如果x在集合Ba中,则2x+1,3x+1 ...

  10. Comet OJ Contest #13 简要题解

    C2 首先用并查集维护\(1\)的连通块,然后用另外一个并查集维护第\(i\)行中,第\(j\)列之后的第一个\(0\)的位置,就是如果当前位置是\(1\)那么它的父亲是它右边的格子,否则是它自己. ...