26

如果这两行代码相同,我很感兴趣:

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

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

4

3 回答 3

32

第一种情况不执行双重分配,它执行两次分配,一个用于托管对象,一个用于shared_ptr.

对于第二种情况,cppreference很好地解释了为什么std::make_shared 通常只执行它所说的一次内存分配(强调我的未来):

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

std::shared_ptr部分它说:

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

make_shared描述与shared_ptr 创建部分中所述的C++11 草案标准一致20.7.2.2.6

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) 更多的内存,以允许内部簿记结构,例如引用计数。——尾注]

make_sharedHerb Sutter在GotW #89 Solution: Smart Pointers中对使用的优点进行了更详细的解释,并指出了一些优点:

  • 它减少了分配开销
  • 它改善了局部性。
  • 避免显式的 new。
  • 避免异常安全问题。

请注意,在使用std::weak_ptr时 使用 make_shared 有一些缺点

于 2014-07-16T11:46:59.560 回答
4

节中cppreference std::shared_ptr的解释Implementation notes

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

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

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

于 2014-07-16T11:54:28.290 回答
1

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

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

于 2014-07-17T09:50:26.017 回答