使用make_shared时会发生什么

时间:2014-07-16 11:42:43

标签: c++ c++11 smart-pointers make-shared

我对这两行代码是否相同感兴趣:

shared_ptr<int> sp(new int(1)); // double allocation?
shared_ptr<int> sp(make_shared<int>(1)); // just one allocation?

如果这是真的,有人可以解释为什么在第二行只有一个分配?

3 个答案:

答案 0 :(得分:32)

第一种情况不执行双重分配,它执行两次分配,一次用于托管对象,另一种用于shared_ptr控制块

对于第二种情况,cppreference有一个很好的解释,为什么std::make_shared 通常只执行一次内存分配(强调我的前进 >):

  

此函数通常为T对象和for分配内存   shared_ptr的控制块具有单个内存分配(它是一个   标准中的非约束性要求。相反,声明   std :: shared_ptr p(new T(Args ...))执行至少两个内存   分配,这可能会产生不必要的开销。

并从std::shared_ptr部分说明:

  

当通过调用std :: make_shared或创建shared_ptr时   std :: allocate_shared,控制块和控制块的内存   使用单个分配创建托管对象。托管对象   在控制块的数据成员中就地构造。什么时候   shared_ptr是通过其中一个shared_ptr构造函数创建的   必须单独分配托管对象和控制块。在   在这种情况下,控制块存储指向被管理对象的指针。

make_shared说明与第20.7.2.2.6 份共享创建

部分中所述的C++11 draft standard一致
template<class T, class... Args> shared_ptr<T> make_shared(Args&&... args);
template<class T, class A, class... Args>
  shared_ptr<T> allocate_shared(const A& a, Args&&... args);
     

[...]

     

备注:实现应该只执行一个内存   分配。 [注意:这提供的效率相当于一个   侵入式智能指针。 - 后注]

     

[注意:这些函数通常会分配更多的内存   sizeof(T)允许内部簿记结构,如   参考计数。 - 后注]

Herb Sutter更详细地解释了在GotW #89 Solution: Smart Pointers中使用make_shared的优势,并指出了一些优势:

  • 减少分配开销
  • 改善了地方。
  • 避免使用明确的新内容。
  • 避免异常安全问题。

使用std::weak_ptr using make_shared has some disadvantages

时请注意

答案 1 :(得分:4)

来自Implementation notes部分的cppreference std::shared_ptr的说明

  

在典型的实现中,std :: shared_ptr只包含两个指针:

     
      
  1. 指向托管对象的指针
  2.   
  3. 指向控制块的指针
  4.         

    当通过调用std :: make_shared或创建shared_ptr时   std :: allocate_shared,控制块和控制块的内存   使用单个分配创建托管对象。托管对象   在控制块的数据成员中就地构造。什么时候   shared_ptr是通过其中一个shared_ptr构造函数创建的   必须单独分配托管对象和控制块。在   在这种情况下,控制块存储指向被管理对象的指针。

答案 2 :(得分:1)

还有一个潜在的微妙错误:在sp(new int)中,你首先分配一个int(其指针被赋予sp),而sp本身必须分配一个控制块(将包含计数器和删除者。)

现在,如果执行此最后一次分配sp失败(内存不足),则会留下一个堆分配的int,其指针不被任何人持有,因此无法删除。 (记忆泄漏)。