62

有什么区别:

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

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

?

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

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

4

3 回答 3

86

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

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

有什么不同?

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

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

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

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


编辑 2020/03/06:

进一步的建议还来自带有相关示例的官方 Microsoft 文档。继续关注示例 1代码段:

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

于 2013-08-18T17:21:31.417 回答
22

来自en.cppreference.com

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

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

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

于 2013-08-18T17:03:45.980 回答
11

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

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

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

于 2014-01-09T14:34:59.430 回答