2013-10-20 101 views
11

只是为了澄清,使用make_unique只会在表达式中有多个分配时添加异常安全性,而不仅仅是一个,是否正确?例如异常安全和make_unique

void f(T*); 

f(new T); 

是完全异常安全(据分配和东西),而

void f(T*, T*); 

f(new T, new T); 

是不是,对不对?

+0

你的问题似乎与自己相矛盾。首先你声明多分配是异常安全的,然后你展示一个例子,这在表面上与所发生的事情相反。 –

+0

@LightnessRacesinOrbit不,我断言多个分配不是异常安全的。我说过“make_unique只在表达式中有多个分配时才会增加异常安全性”,这意味着它仅为一次分配增加了任何内容。 – Kal

+0

啊!是的,好的,然后:) –

回答

21

不仅当你有多个分配,但只要你可以扔在不同的地方。这样考虑:

f(make_unique<T>(), function_that_can_throw()); 

对战:

f(unique_ptr<T>(new T), function_that_can_throw()); 

在第二种情况下,编译器允许调用(按顺序):

  • new T
  • function_that_can_throw()
  • unique_ptr<T>(...)

显然如果function_that_can_throw实际上抛出然后你泄漏。 make_unique可以防止这种情况。

当然,第二个分配(就像在你的问题中)只是function_that_can_throw()的特殊情况。

作为一般的经验法则,只需使用make_unique,以便您的代码是一致的。当你需要一个unique_ptr时它总是正确的(阅读:异常安全),并且它对性能没有任何影响,所以没有理由不使用它(而实际上而不是使用它引入了很多陷阱)。

+2

谢谢,这就是我一直在寻找的东西。对不起,毁了你的2^13代表。 – Kal

+1

@Kal没关系,我现在瞄准2^14 ...;) – syam

6

我还以为你会更好的东西比较实际使用std::unique_ptr<T>

void f(std::unique_ptr<T>); 

f(std::unique_ptr<T>(new T)); 
f(std::make_unique<T>()); 

如果引发异常无论这些调用可能泄漏。然而

void f(std::unique_ptr<T>, std::unique_ptr<T>); 

g(std::unique_ptr<T>(new T), std::unique_ptr<T>(new T)); 
g(std::make_unique<T>(), std::make_unique<T>()); 

在这种情况下,使用std::unique_ptr<T>明确的版本可以泄漏,如果一个异常被抛出(因为编译器可能会启动建设无论是临时工的前评估new -expressions)。

2

作为C++ 17,异常安全问题是由[expr.call]

的参数,包括每个关联值计算和副作用的初始化一个重新措辞固定,是不定相对于该测序任何其他参数。

这里不定测序指一个之前另一个序列,但没有指定其它。

f(unique_ptr<T>(new T), function_that_can_throw()); 

只能有两个执行

可能为了
  1. new Tunique_ptr<T>::unique_ptrfunction_that_can_throw
  2. function_that_can_thrownew Tunique_ptr<T>::unique_ptr

这意味着它现在是异常安全。