4

我一直在阅读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按照我的理解,新构建的无论如何都会泄漏。

4

1 回答 1

13

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

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

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

  1. new A
  2. new B// 可能会抛出!
  3. 构造unique_ptr<A>
  4. 构造unique_ptr<B>
  5. 称呼do_work

如果new B抛出,那么你已经泄露了A,因为没有unique_ptr构造过。

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


也就是说,给定:

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

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

  1. 称呼make_unique<A>
  2. 称呼make_unique<B>
  3. 称呼do_work

或者

  1. 称呼make_unique<B>
  2. 称呼make_unique<A>
  3. 称呼do_work

在没有拥有 s 的情况下,在有新对象漂浮的地方进行泄漏是unique_ptr不可能的。

于 2015-05-29T02:00:03.693 回答