我对这两行代码是否相同感兴趣:
shared_ptr<int> sp(new int(1)); // double allocation?
shared_ptr<int> sp(make_shared<int>(1)); // just one allocation?
如果这是真的,有人可以解释为什么在第二行只有一个分配?
答案 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
份共享创建
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
的优势,并指出了一些优势:
答案 1 :(得分:4)
来自Implementation notes
部分的cppreference std::shared_ptr的说明
在典型的实现中,std :: shared_ptr只包含两个指针:
- 指向托管对象的指针
- 指向控制块的指针
醇>当通过调用std :: make_shared或创建shared_ptr时 std :: allocate_shared,控制块和控制块的内存 使用单个分配创建托管对象。托管对象 在控制块的数据成员中就地构造。什么时候 shared_ptr是通过其中一个shared_ptr构造函数创建的 必须单独分配托管对象和控制块。在 在这种情况下,控制块存储指向被管理对象的指针。
答案 2 :(得分:1)
还有一个潜在的微妙错误:在sp(new int)
中,你首先分配一个int(其指针被赋予sp
),而sp本身必须分配一个控制块(将包含计数器和删除者。)
现在,如果执行此最后一次分配sp
失败(内存不足),则会留下一个堆分配的int,其指针不被任何人持有,因此无法删除。 (记忆泄漏)。