【问题标题】:std::shared_ptr initialization: make_shared<Foo>() vs shared_ptr<T>(new Foo) [duplicate]std::shared_ptr 初始化:make_shared<Foo>() vs shared_ptr<T>(new Foo) [重复]
【发布时间】:2013-08-20 12:35:14
【问题描述】:

两者有什么区别:

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

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

?

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

P。 S. 很确定这个问题一定已经回答过了,但我找不到类似的问题。

【问题讨论】:

  • 第二个必须是std::make_shared&lt;int&gt;()
  • 是的,但在这种情况下不是。始终使用make_shared。有关详细信息,请参阅以下 URL:herbsutter.com/2013/05/29/gotw-89-solution-smart-pointers
  • @Deduplicator:我的问题怎么会和一年后的问题重复?
  • @VioletGiraffe:我认为另一个稍微好一点,它们覆盖了相同的领域。年龄只是作为决定因素出现(尽管不幸的是它在解释性文本中过于突出),并且年龄较大的问题有更高的机会被完善。
  • @Deduplicator:很公平。虽然我觉得我的标题也更清楚了。

标签: c++ c++11 shared-ptr smart-pointers


【解决方案1】:

这两个例子都过于冗长了:

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,因为它更有效。正如另一个答案中所述,它还避免了内存泄漏的任何可能性,因为您永远没有指向托管对象的原始指针。

但是,如 cmets 中所述,如果仍有弱指针阻止共享计数被删除,则在销毁对象时不会释放内存。


编辑 2020/03/06:

更多建议也来自official Microsoft documentation 以及相关示例。继续关注示例 1 sn-p:

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

【讨论】:

  • 它有一个缺点:只要有指向对象的弱指针,内存块就会一直保留。
  • @Xeo:谢谢,我忘记了。
  • @Xeo 你能详细说明一下弱ptr问题吗?创建弱指针不是为了保存内存,那么为什么会出现这种情况?
  • @Trismegistos:因为保存弱指针和共享指针的数据和计数器的共享块只能在最后一个关联的 weak_ptr 被销毁后才能释放 - 否则,@987654327 将如何@知道它的父母已经走了吗?
  • @Xeo 为什么 make_shared 是这种情况,而 std::shared_ptr 构造函数不是这种情况?
【解决方案2】:

来自en.cppreference.com

相比之下,声明std::shared_ptr&lt;T&gt; p(new T(Args...))执行至少两次内存分配,这可能会产生不必要的开销。

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

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

【讨论】:

  • 谢谢。太糟糕了,Mac 上的shared_ptrmake_shared 存在问题(它们仍在tr1 命名空间中,所以我必须定义宏来使用共享指针编写可移植代码)。我的意思是,使用make_shared 需要额外的宏。
  • 那很糟糕。您使用的是哪个编译器?在 Debian 中 g++ 4.7 没有这个问题。
  • @VioletGiraffe:在 Mac 上,您可以指定 -stdlib=libc++(在 Xcode 中,在构建设置中找到“C++ 标准库”并选择“libc++”)。这将为您提供 C++11 std::lib。
  • @HowardHinnant:嗯!是官方的吗?就像没有越野车一样?
  • Apple 正式支持它回到 10.7,并无限期向前。
【解决方案3】:

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多