2013-10-20 77 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

這意味着它現在是異常安全。