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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18301511/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 21:52:39  来源:igfitidea点击:

std::shared_ptr initialization: make_shared<Foo>() vs shared_ptr<T>(new Foo)

c++c++11shared-ptrsmart-pointers

提问by Violet Giraffe

What's the difference between:

有什么区别:

std::shared_ptr<int> p = std::shared_ptr<int>( new int );

and

std::shared_ptr<int> p = std::make_shared< int >();

?

?

Which one should I prefer and why?

我应该更喜欢哪一个,为什么?

P. S. Pretty sure this must have been answered already, but I can't find a similar question.

PS 很确定这一定已经回答了,但我找不到类似的问题。

回答by Mike Seymour

Both examples are rather more verbose than necessary:

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

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

What's the difference?

有什么不同?

The main difference is that the first requires two memory allocations: one for the managed object (new int), and one for the reference count. make_sharedshould allocate a single block of memory, and create both in that.

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

Which one should I prefer and why?

我应该更喜欢哪一个,为什么?

You should usually use make_sharedas it's more efficient. As noted in another answer, it also avoids any possibility of a memory leak, since you never have a raw pointer to the managed object.

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

However, as noted in the comments, it has a potential disadvantage that the memory won't be released when the object is destroyed, if there are still weak pointers preventing the shared count from being deleted.

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



EDIT 2020/03/06:

编辑 2020/03/06:

Further recommendations come also from the official Microsoft documentationwith associated examples. Keep the focus on the Example 1snippet:

进一步的建议也来自带有相关示例的官方 Microsoft 文档。将重点放在示例 1代码段上:

Whenever possible, use the make_shared function to create a shared_ptr when the memory resource is created for the first time. make_shared is exception-safe. It uses the same call to allocate the memory for the control block and the resource, which reduces the construction overhead. If you don't use make_shared, then you have to use an explicit new expression to create the object before you pass it to the shared_ptr constructor. The following example shows various ways to declare and initialize a shared_ptr together with a new object.

在第一次创建内存资源时,尽可能使用 make_shared 函数创建一个 shared_ptr。make_shared 是异常安全的。它使用相同的调用为控制块和资源分配内存,减少了构建开销。如果不使用 make_shared,则必须在将对象传递给 shared_ptr 构造函数之前使用显式 new 表达式来创建对象。以下示例显示了声明和初始化 shared_ptr 以及新对象的各种方法。

回答by Adri C.S.

From en.cppreference.com

来自en.cppreference.com

In contrast, the declaration std::shared_ptr<T> p(new T(Args...))performs at least two memory allocations, which may incur unnecessary overhead.

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

Moreover, f(shared_ptr<int>(new int(42)), g())can lead to memory leak if g throws an exception. This problem doesn't exist if make_shared is used.

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

So I would recommend the make_sharedapproach if possible.

所以make_shared如果可能的话,我会推荐这种方法。

回答by doc_ds

Be aware that make_sharedlimits you to using the default allocation/deallocation functions so if you want to have more control, make_sharedis not an option. In other words, something like

请注意,make_shared限制您使用默认分配/解除分配功能,因此如果您想拥有更多控制权,make_shared这不是一个选项。换句话说,像

std::shared_ptr<uint8_t>(p, [](uint8_t *p){ /*user code */}); 

is impossible using make_shared. One could use allocate_sharedinstead, but only the allocator can be specified, not a deleter. Sometimes one need to control allocation and deletion of the wrapped class.

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