【问题标题】:std::shared_ptr Exception Safetystd::shared_ptr 异常安全
【发布时间】:2013-11-18 17:04:33
【问题描述】:

我刚刚读到this page 意识到std::shared_ptr 的构造函数只有一个指针参数不是noexcept。

因此以下代码包含可能的内存泄漏:

std::shared_ptr<int> p3 (new int);

原因是可能发生两次分配:

  • 调用构造函数之前的第一个
  • shared_ptr 构造函数中的第二个(这就是在 VS 2012 中发生的情况)

这里有两个问题:

如果第二次分配抛出异常,是不是第一次的内存泄漏?

如果答案是肯定的:

使用 std::shared_ptr 的正确习惯用法是什么?

  • 使用 make_shared
  • 将第一个分配的所有权授予 std::unique_ptr 然后转移所有权
  • 其他想法?

【问题讨论】:

  • 哦,天哪,一个关于智能指针的有趣问题。我认为这已经不可能了。 +1
  • The other reference 已经有了这个问题的答案...

标签: c++ c++11 memory-leaks shared-ptr


【解决方案1】:
template<class Y> explicit shared_ptr(Y* p);

[util.smartptr.shared.const]/6 抛出bad_alloc,或者当无法获取内存以外的资源时,实现定义的异常.
[util.smartptr.shared.const]/7 异常安全:如果抛出异常,则调用delete p

所以不,没有内存泄漏。

【讨论】:

    【解决方案2】:

    迟到的答案,但最好使用make_shared() 来确保异常安全,如 GotW #102 中所述:以下代码不是异常安全:

     f( std::shared_ptr<T1>{ new T1 }, std::shared_ptr<T2>{ new T2 } );
    

    而以下是:

    f( std::make_shared<T1>(), std::make_shared<T2>() );
    

    【讨论】:

    • 另外,替换可能更有效。
    • 在某些情况下您不能使用make_shared,即在继承类型上调用new,而shared_ptr 被模板化以保存基本类型。
    • 聚会有点晚了,但我来这里是为了另一个用例,这是不可能的:当您需要指定自定义释放器时。但有一个简单的解决方法:永远不要在同一语句中多次调用 std::shared_ptr{}。
    • 另一种你可能想要使用 std::make_shared() 的情况:如果从使用 std 制作的 shared_ptr 获得的比 shared_ptr 寿命更长的 weak_ptr ::make_shared(),对象 T 占用的内存将持续存在,直到所有弱所有者也被销毁。 (为什么?在实践中,std::make_shared 比 shared_ptr 构造函数更有效,因为它只为 both 对象 T 和控制块执行 一次分配,而不是2.weak_ptr 需要控制块,所以你会被这个整体块卡住。)
    猜你喜欢
    • 2016-08-05
    • 2013-01-07
    • 1970-01-01
    • 2015-03-24
    • 2013-05-15
    • 2019-06-07
    • 2011-08-01
    相关资源
    最近更新 更多