make_unique 的异常安全:为什么 f(new T) 异常安全

Exceptionsafety of make_unique: Why is f(new T) exception safe

我一直在阅读 GOTW102,想知道为什么 make_unique 比其他情况更安全,或者为什么 f(new T(...)) 比 [=14] 更安全=].

博客中的 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 无论如何都会被泄露。

原因是在函数调用或类似的调用中,参数不包含序列点(不是 "sequenced before")。例如:

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 构造放入它自己的函数中消除了这个问题,因为编译器不允许并发执行函数体(因此 "new" 和“构造 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

在没有拥有 unique_ptr 的新对象四处漂浮的地方泄漏是不可能的。