std :: shared_ptr初始化:make_shared <Foo>()vs shared_ptr <T>(new Foo)

Vio*_*ffe 43 c++ smart-pointers shared-ptr c++11

有什么区别:

std::shared_ptr<int> p = std::shared_ptr<int>( new int );
Run Code Online (Sandbox Code Playgroud)

std::shared_ptr<int> p = std::make_shared< int >();
Run Code Online (Sandbox Code Playgroud)

我应该选择哪一个?为什么?

PS相当肯定这已经得到了答案,但我找不到类似的问题.

Mik*_*our 64

这两个例子都比必要的更冗长:

std::shared_ptr<int> p(new int);  // or '=shared_ptr<int>(new int)' if you insist
auto p = std::make_shared<int>(); // or 'std::shared_ptr<int> p' if you insist
Run Code Online (Sandbox Code Playgroud)

有什么不同?

主要区别在于第一个需要两个内存分配:一个用于托管对象(new int),另一个用于引用计数.make_shared应该分配一块内存,并在其中创建.

我应该选择哪一个?为什么?

您通常应该使用make_shared它,因为它更有效.如另一个答案中所述,它还避免了任何内存泄漏的可能性,因为您从未拥有指向托管对象的原始指针.

但是,正如评论中所指出的,它有一个潜在的缺点,即如果仍有弱指针阻止共享计数被删除,则在销毁对象时不会释放内存.

  • 它有一个缺点:只要存在指向对象的弱指针,内存块就会保持不变. (20认同)
  • @Xeo:谢谢,我已经忘了这件事. (2认同)
  • @Xeo 你能详细说明弱 ptr 问题吗?创建弱指针是为了不保存内存,那么为什么在这种情况下会出现这种情况? (2认同)
  • @Trismegistos:因为包含弱和共享指针的数据和计数器的共享块只能在最后一个关联的`weak_ptr`被销毁后释放 - 否则,`weak_ptr`如何知道它的父元素已经消失? (2认同)
  • @Xeo为什么这是make_shared的情况,而不是std :: shared_ptr构造函数的情况? (2认同)
  • @Trismegistos:未被释放的块对于两者都是相同的.不同之处在于`make_shared`将共享对象_into_放入阻塞,而指针的正常构造只存储 - 指针,一旦共享计数达到0,就可以释放它. (2认同)

Adr*_*.S. 16

来自en.cppreference.com

相反,声明std::shared_ptr<T> p(new T(Args...)) 至少执行两次内存分配,这可能会产生不必要的开销.

此外,如果g抛出异常,f(shared_ptr<int>(new int(42)), g()) 可能导致内存泄漏.如果使用make_shared,则不存在此问题.

所以我会make_shared尽可能推荐这种方法.


小智 9

请注意,make_shared限制使用默认分配/释放功能,因此如果您想要更多控制,make_shared则不能选择.换句话说,就像

std::shared_ptr<uint8_t>(p, [](uint8_t *p){ /*user code */}); 
Run Code Online (Sandbox Code Playgroud)

不可能使用make_shared.可以使用allocate_shared,但只能指定分配器,而不是删除器.有时需要控制包装类的分配和删除.