我想知道这两行代码是否相同:
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?
如果这是真的,有人能解释一下为什么第二行只有一个分配吗?
从std::shared_ptr部分可以看到:此函数通常使用单个内存分配为T对象和shared_ptr的控制块分配内存(这是标准中的非约束性要求)。相比之下,声明std::shared_ptr p(new T(Args...))至少执行两次内存分配,这可能会产生不必要的开销。
20.7.2.2.6
节“shared_ptr creation”中提到。
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);
[...]
Remarks: Implementations should perform no more than one memory allocation. [ Note: This provides efficiency equivalent to an intrusive smart pointer. —end note ]
[ Note: These functions will typically allocate more memory than sizeof(T) to allow for internal bookkeeping structures such as the reference counts. —end note ]
Herb Sutter在GotW#89 Solution:Smart Pointers中更详细地解释了使用make_shared
的优点,并指出了一些优点:
请注意,当使用std :: weak_ptr时,使用make_shared有一些缺点。
cppreference std::shared_ptr 的 实现注释
部分解释如下:
在典型的实现中,std::shared_ptr 仅持有两个指针:
- 指向托管对象的指针
- 指向控制块的指针
当通过调用 std::make_shared 或 std::allocate_shared 创建 shared_ptr 时,控制块和托管对象的内存都是通过单个分配创建的。托管对象将会原地构造在控制块的数据成员中。当通过 shared_ptr 构造函数创建 shared_ptr 时,托管对象和控制块必须分别进行分配。在这种情况下,控制块存储一个指向托管对象的指针。
还有一个潜在的细微错误:在 sp(new int)
中,您首先分配一个 int(其指针被赋予给 sp
),然后 sp 本身必须分配一个控制块(其中包含计数器和删除器)。
现在,如果进行此最后一次分配时 sp
失败(内存不足),则会留下一个由堆分配的 int,其指针没有任何人持有,因此无法删除。(内存泄漏)。
int
进行双重分配。它只是两个单独的分配:一个用于int
对象,另一个用于shared_ptr
控制块。第二行只是一次同时分配int
和控制块的单个分配。 - Joseph Mansfieldmake_shared
分配了int
和控制块,因此可以自由地一次性分配两者。在第一种情况下,您分配了int
,而shared_ptr
的构造函数分配了控制块,没有办法将这两个分配合并。 - nwpmake_shared
只执行一次分配内存的操作并不是保证,仅仅只是在实现中有可能做到。但如果你的实现没有执行这种优化,你应该向你的供应商提出投诉(至少 GCC、LLVM 和 MSVC 实现都可以做到,boost::make_shared
也可以)。 - Jonathan Wakely