C++11使用make_shared的优势和劣势
2017-06-06 19:26
393 查看
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 23 | 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"))); |
new Lhs(“foo”))
new Rhs(“bar”))
std::shared_ptr
std::shared_ptr
好了, 现在我们假设在第 2 步的时候, 抛出了一个异常 (比如 out of memory, 总之, Rhs 的构造函数异常了), 那么第一步申请的 Lhs 对象内存泄露了. 这个问题的核心在于, shared_ptr 没有立即获得裸指针.
我们可以用如下方式来修复这个问题.
1 23 | 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 Pointerscppreference.com – std::make_shared
转载自:http://bitdewy.github.io/blog/2014/01/12/why-make-shared/
相关文章推荐
- C++11使用make_shared的优势和劣势
- c++11 条款21:尽量使用std::make_unique和std::make_shared而不直接使用new
- C++11智能指针之优先使用std::make_unique和std::make_shared而不是直接使用new
- c++11 条款21:尽量使用std::make_unique和std::make_shared而不直接使用new
- c++11 条款21:尽量使用std::make_unique和std::make_shared而不直接使用new
- C++11智能指针之shared_ptr的使用(1)
- Item 21: 比起直接使用new优先使用std::make_unique和std::make_shared
- C++11中使用shared_ptr和unique_ptr管理动态数组
- 使用 Node.js 的优势和劣势都有哪些?转于知乎
- c++11 & 14: unique_ptr shared_ptr std::make_unique(c++14)
- 使用框架开发的优势和劣势
- 系统开发中存储过程使用的优势和劣势
- C++11智能指针之使用shared_ptr实现多态
- 使用ASP的优势和劣势
- Effective Modern C++ 条款21 比起直接使用new,更偏爱使用std::make_unique和std::make_shared
- C++11 shared_ptr 智能指针 的使用,避免内存泄露
- 从知乎的反馈看node.js优势/劣势以及使用厂商
- 使用框架开发的优势和劣势
- 使用 Node.js 的优势和劣势都有哪些?
- C++11: forwarding parameter packs and define my own version of make_shared