如果这两行代码相同,我很感兴趣:
shared_ptr<int> sp(new int(1)); // double allocation?
shared_ptr<int> sp(make_shared<int>(1)); // just one allocation?
如果这是真的,有人可以解释为什么第二行只有一个分配吗?
如果这两行代码相同,我很感兴趣:
shared_ptr<int> sp(new int(1)); // double allocation?
shared_ptr<int> sp(make_shared<int>(1)); // just one allocation?
如果这是真的,有人可以解释为什么第二行只有一个分配吗?
第一种情况不执行双重分配,它执行两次分配,一个用于托管对象,一个用于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_shared
Herb Sutter在GotW #89 Solution: Smart Pointers中对使用的优点进行了更详细的解释,并指出了一些优点:
请注意,在使用std::weak_ptr时 使用 make_shared 有一些缺点。
节中cppreference std::shared_ptr的解释Implementation notes
在典型的实现中,std::shared_ptr 只保存两个指针:
- 指向托管对象的指针
- 指向控制块的指针
当通过调用 std::make_shared 或 std::allocate_shared 创建 shared_ptr 时,控制块和托管对象的内存都是使用单个分配创建的。托管对象在控制块的数据成员中就地构造。通过 shared_ptr 构造函数之一创建 shared_ptr 时,必须分别分配托管对象和控制块。在这种情况下,控制块存储一个指向被管理对象的指针。
还有一个潜在的微妙错误:sp(new int)
首先分配一个 int (其指针被赋予sp
),而不是 sp 本身必须分配一个控制块(将包含计数器和删除器)。
现在,如果最后一次分配sp
失败(内存不足),您将留下一个堆分配的 int,其指针不被任何人持有,因此无法删除。(内存泄漏)。