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
std::shared_ptr initialization: make_shared<Foo>() vs shared_ptr<T>(new Foo)
提问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_shared
should 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_shared
as 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
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_shared
approach if possible.
所以make_shared
如果可能的话,我会推荐这种方法。
回答by doc_ds
Be aware that make_shared
limits you to using the default allocation/deallocation functions so if you want to have more control, make_shared
is 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_shared
instead, 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
改用,但只能指定分配器,而不是删除器。有时需要控制包装类的分配和删除。