【问题标题】:Exceptionsafety of make_unique: Why is f(new T) exception safemake_unique 的异常安全性:为什么 f(new T) 异常安全
【发布时间】:2015-05-29 00:58:54
【问题描述】:

我一直在阅读GOTW102,想知道为什么make_unique 比其他情况更安全,或者详细说明为什么f(new T(...))f(new T1(...), new T2(...)) 更安全。

博客中的make_unique 实现如下:

template<typename T, typename ...Args>
std::unique_ptr<T> make_unique( Args&& ...args )
{
    return std::unique_ptr<T>( new T( std::forward<Args>(args)... ) );
}

现在我想知道f(new T(...)) 是否通常是异常安全的(无泄漏),或者在make_unique 的情况下是否只是异常安全,因为std::unique_ptr 的构造函数不会抛出的附加知识? (因为如果按照我的理解,新构建的T 无论如何都会被泄露。

【问题讨论】:

标签: c++ exception c++14 exception-safety


【解决方案1】:

原因是在函数调用或类似调用中,参数不引入序列点(不是“之前排序”)。例如:

do_work(unique_ptr<A>(new A), unique_ptr<B>(new B));

允许编译器生成如下代码:

  1. new A
  2. new B // 可能会抛出!
  3. 构造unique_ptr&lt;A&gt;
  4. 构造unique_ptr&lt;B&gt;
  5. 致电do_work

如果new B 抛出,那么您已经泄露了A,因为从未构造过unique_ptr

unique_ptr 构造放到它自己的函数中可以消除这个问题,因为编译器不允许同时执行函数体(所以“新建”和“构造unique_ptr”步骤需要一起完成)。


也就是说,给定:

do_work(make_unique<A>(), make_unique<B>())

编译器必须生成如下代码:

  1. 致电make_unique&lt;A&gt;
  2. 致电make_unique&lt;B&gt;
  3. 致电do_work

  1. 致电make_unique&lt;B&gt;
  2. 致电make_unique&lt;A&gt;
  3. 致电do_work

不可能在没有拥有unique_ptrs 的情况下四处浮动有新对象的泄漏。

【讨论】:

  • 我了解大部分,我的问题更集中在make_unique。它被定义为执行unique_ptr&lt;A&gt;(new A) 的函数。我从哪里得到保证 unique_ptr&lt;A&gt;new A 完成后不会抛出(我没有看到一点可能抛出的代码 => 它不会抛出)。但是如果unique_ptr 的构造函数可以抛出,它就不是异常安全的(又名A 会被泄露),对吧?
  • @ted:你得到了保证,因为 C++11 20.7.1.2 [unique.ptr.single]/1: // 20.7.1.2.1, constructors [...] explicit unique_ptr(pointer p) noexcept; noexcept
  • 顺便说一下,shared_ptr 的构造函数来自原始指针可以 抛出(它必须分配控制块),但在这种情况下保证会删除指针,所以什么都没有泄露。
  • @T.C.:我能找到这方面的参考吗?
  • @ted 我说的是shared_ptr,而不是unique_ptr
猜你喜欢
  • 2013-10-28
  • 2016-06-16
  • 1970-01-01
  • 2011-01-24
  • 2010-12-02
  • 2016-11-20
  • 2015-09-13
  • 2014-09-28
相关资源
最近更新 更多