只是为了澄清一下,make_unique
当您在一个表达式中有多个分配时,使用只增加异常安全性,而不仅仅是一个,对吗?例如
void f(T*);
f(new T);
是完全异常安全的(就分配和东西而言),而
void f(T*, T*);
f(new T, new T);
是不正确的?
只是为了澄清一下,make_unique
当您在一个表达式中有多个分配时,使用只增加异常安全性,而不仅仅是一个,对吗?例如
void f(T*);
f(new T);
是完全异常安全的(就分配和东西而言),而
void f(T*, T*);
f(new T, new T);
是不正确的?
不仅当你有多个分配时,而且当你可以在不同的地方抛出时。考虑一下:
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
以使您的代码保持一致。当您需要 a 时它总是正确的(阅读:异常安全)unique_ptr
,并且它对性能没有任何影响,因此没有理由不使用它(实际上不使用它会引入很多陷阱)。
从 C++17 开始,异常安全问题通过改写[expr.call]得到修复
参数的初始化,包括每个相关的值计算和副作用,相对于任何其他参数的初始化是不确定的。
这里不确定排序意味着一个在另一个之前排序,但没有指定哪个。
f(unique_ptr<T>(new T), function_that_can_throw());
只能有两种可能的执行顺序
new T
unique_ptr<T>::unique_ptr
function_that_can_throw
function_that_can_throw
new T
unique_ptr<T>::unique_ptr
这意味着它现在是异常安全的。
我认为你最好比较实际使用的东西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
在构造任何一个临时变量之前开始评估 - 表达式)。