探究make_shared效率

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

参考

  • GotW #89 Solution: Smart Pointers
  • cppreference.com – std::make_shared

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/548151.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vs2012里用easyUI,显示不正常

vs2012里用easyUI&#xff0c;显示不正常&#xff0c;什么时候可以解决转载于:https://www.cnblogs.com/zhangxj/archive/2013/01/05/2846235.html

asp.net实现ftp上传代码(解决大文件上传问题)

原来使用asp.net上传控件上传 那个虽然简单但是页面不是很友好 然后就用了uploadify上传控件 这个控件虽然界面友好 但是大文件还是不能上传 而且在不同的浏览器会出现session丢失问题 所以我到了个ftp上传的方法 以下是具体代码 View Code?11 using System; 2 using System…

关于豆瓣电台收费的思考

大家讨论的热火朝天啊大家的问题&#xff1a;电台的盈利模型是不是只有广告我觉得电台的盈利只靠广告是不行的&#xff0c;所谓电台就是主要是多播和广播&#xff0c;是相对传统电台来的。传统电台涉及硬件成本低。广告可以&#xff0c;互联网电台依靠广告盈利&#xff0c;除非…

做自己的伯乐

读很多古代大家的故事&#xff0c;就发现贾谊、苏轼、李白等人生不逢时&#xff0c;怀才不遇&#xff0c;不被帝王将相所识并所用&#xff0c;实现自己的政治抱负。笔者细观周围好多朋友和同事&#xff0c;在一起聚会时&#xff0c;常常也发出类似的慨叹&#xff0c;刨去当前企…

MVC Layout布局系统

原文&#xff1a;http://www.cnblogs.com/highend/archive/2011/04/18/asp_net_mvc3_layout.html Layout页:该家伙其实就相当于原来的Master文件. Partial页:相当于原来的UserControl View页: View Page with Layout:等同于原来的View Content Page.它的功能只是为了实现原来在…

tolua++

一.tolua简介tolua是一种第三方的软件包,可以为Lua提供面向对象的特性,这样我们就可以使用Lua来编写使用C语言库的脚本文件.二.tolua的编译. tolua的主页在http://www.codenix.com/~tolua/,目前的最新版本是1.0.7,为了使用tolua,我们需要三个文件: 1.bin/tolua[.exe…

IE6PNG8PNG24test

2019独角兽企业重金招聘Python工程师标准>>> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns"http://www.w3.org/1999/xhtml"&…

Java线程(七):锁对象Lock-同步问题更完美的处理方式 .

Lock是java.util.concurrent.locks包下的接口&#xff0c;Lock 实现提供了比使用synchronized 方法和语句可获得的更广泛的锁定操作&#xff0c;它能以更优雅的方式处理线程同步问题&#xff0c;我们拿Java线程(二)中的一个例子简单的实现一下和sychronized一样的效果&#xff…

ipconfig命令指南

ipconfig /all 显示本机TCP/IP配置的详细信息 ipconfig /relase DHCP客户端手动释放IP地址 ipconfig /renew DHCP客户端向服务器刷新请求&#xff08;具有更新的作用&#xff09; ipconfig /flushdns 清除本地的DNS缓存内容 ipconfig /regesterdns dns客户端手工向服务器注册 i…

linux --常用命令

一、文件操作 1.创建文件夹 mkdir /var/www/test 2.复制文件 cp file1 file2 复制文件file1.php 的内容到文件file2中。 3.cp -b file1.php file2.php 备份file1.php并重命名为file2.php 4.复制文件夹和子文件夹: cp -R scripts scripts1 从 scripts 复制文件夹和子文件…

调整 Windows系统参数网址

https://www.ibm.com/docs/zh/was-nd/9.0.5?topicsystems-tuning-windows

多路复用与设置阻塞、非阻塞模式

多路复用与设置阻塞、非阻塞模式 - To be, or not to be: that is the question - 博客频道 - CSDN.NET多路复用与设置阻塞、非阻塞模式 分类&#xff1a; Linux/Unix C/C Network Program 2009-10-06 20:30 202人阅读 评论(0) 收藏 举报阻塞和非阻塞模式使用fcntl()可以进行设…

c++指定枚举占一个字节

//这样的写法,指定这个枚举占1字节 enum class watch_state : uint8_t { initialized, listening, pending_close, };

openssl 1.1.1编译语句

Perl Configure VC-WIN64A no-asm --openssldir"D:\openssl_lib" perl Configure VC-WIN32 no-asm --openssldir"D:\openssl_lib"

开发 Windows 8 Bing地图应用(2)

下面是对使用JavaScript的Bing Maps Trip Optimizer示例的介绍&#xff0c;讲述应用的JavaScript部分组织形式&#xff0c;本地的上下文和网络上下文之间的通信。 WinRT需要访问网络的代码&#xff0c;下面是一些需要访问网络的活动示例。 q 加载一个外部JavaScript文件&#x…

http协议知识msdn

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Protocol_upgrade_mechanism

使用bash编写Linux shell脚本--复合命令

来源&#xff1a;http://blog.csdn.net/fox_lht/article/details/5897336 除了最简单的脚本&#xff0c;你很少想要执行每一个命令。执行一组命令或者重复执行一组命令若干次比执行单个命令更加有助。复合命令是将命令封装在一组其他命令中。 从可读性来说&#xff0c;封装后的…

简明Linux命令行笔记:finger

用来显示用户的相关信息 finger [options] [user-list] finger用来显示用户名、用户全名、终端设备号和登录时间等信息 options用来控制finger的显示内容&#xff0c;user-list用来指定finger要显示的用户列表 finger可以在被地系统和远程系统上检索信息 参数 不带任何参数时&a…

逻辑右移和算术右移区别

逻辑右移就是不考虑符号位&#xff0c;右移一位&#xff0c;左边补零即可。 算术右移需要考虑符号位&#xff0c;右移一位&#xff0c;若符号位为1&#xff0c;就在左边补1,&#xff1b;否则&#xff0c;就补0。 所以算术右移也可以进行有符号位的除法&#xff0c;右移,n位就…

再谈C#委托与事件

转自&#xff1a;http://ruizhinet.blog.163.com/blog/static/9921382820092801032681/ 之前写过一篇关于C#委托与事件的文章&#xff08;见《C#委托和事件例析》&#xff09;&#xff0c;不过还是收到一些网友的提问。所以&#xff0c;今天再换另一个角度来详解一下这个问题。…