Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Exception safety and make_unique

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?

like image 690
Kal Avatar asked Oct 20 '13 00:10

Kal


People also ask

Does make_unique throw exception?

A little late, but make_unique can itself throw according to cppreference: make_unique "may throw std::bad_alloc or any exception thrown by the constructor of T.

What is make_unique?

You can use make_unique to create a unique_ptr to an array, but you cannot use make_unique to initialize the array elements. C++ Copy. // Create a unique_ptr to an array of 5 integers. auto p = make_unique<int[]>(5); // Initialize the array. for (int i = 0; i < 5; ++i) { p[i] = i; wcout << p[i] << endl; }

What does the exception safe programming mean?

Exception safe programming is programming so that if any piece of code that might throw an exception does throw an exception, then the state of the program is not corrupted and resources are not leaked. Getting this right using traditional methods often results in complex, unappealing and brittle code.

What does make_unique return C++?

template<class U> unique_ptr<U> make_unique(U&& value); Returns: A unique_ptr to an object of type U , initialized to move(value) .


2 Answers

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).

like image 66
syam Avatar answered Sep 18 '22 19:09

syam


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.

like image 27
Passer By Avatar answered Sep 17 '22 19:09

Passer By