Exception safety and make_unique

大兔子大兔子 提交于 2019-12-28 04:13:04

问题


Just to clarify, using make_unique only adds exception safety when you have multiple allocations in an expression, not just one, correct? For example

void f(T*);

f(new T);

is perfectly exception safe (as far as allocations and stuff), while

void f(T*, T*);

f(new T, new T);

is not, correct?


回答1:


Not only when you have multiple allocations, but whenever you can throw at different places. Consider this:

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

Versus:

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

In the second case, the compiler is allowed to call (in order):

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

Obviously if function_that_can_throw actually throws then you leak. make_unique prevents this case.

And of course, a second allocation (as in your question) is just a special case of function_that_can_throw().

As a general rule of thumb, just use make_unique so that your code is consistent. It is always correct (read: exception-safe) when you need a unique_ptr, and it doesn't have any impact on performance, so there is no reason not to use it (while actually not using it introduces a lot of gotchas).




回答2:


I'd think you'd be better off comparing things actually using std::unique_ptr<T>:

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

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

Neither of these calls can leak if there is an exception being thrown. However

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>());

In this case, the version using std::unique_ptr<T> explicitly can leak if an exception is thrown (because the compiler might start evaluating the new-expressions before constructing either of the temporaries).




回答3:


As of C++17, the exception safety issue is fixed by a rewording of [expr.call]

The initialization of a parameter, including every associated value computation and side effect, is indeterminately sequenced with respect to that of any other parameter.

Here indeterminately sequenced means that one is sequenced before another, but it is not specified which.

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

Can have only two possible order of execution

  1. new T unique_ptr<T>::unique_ptr function_that_can_throw
  2. function_that_can_throw new T unique_ptr<T>::unique_ptr

Which means it is now exception safe.



来源:https://stackoverflow.com/questions/19472550/exception-safety-and-make-unique

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!