From this thread, we know that the following code is exception-safe (assuming that T( U(std::move(v)) )
is exception-safe, e.g., does not throw, which is library user's responsibility).
auto p = new T( U(std::move(v)) );
The key point here is that the initializer expression U(std::move(v))
is evaluated after memory allocation. Now consider the std::make_unique()
counterpart.
auto p = std::make_unique<T>( U(std::move(v)) );
The initializer expression U(std::move(v))
is evaluated even before std::make_unique()
is called. If memory allocation failed thereafter, v
would have already been moved/modified, providing no strong exception safety. However, if we write
std::unique_ptr<T> p(new T( U(std::move(v)) ));
The new-expression mechanism kicks-in, and we regain strong exception safety. Looks like an exception-safe make_unique
has to be a macro.
#define MAKE_UNIQUE(T, ...) ::std::unique_ptr<T>(new T(__VA_ARGS__))
I'm new to exception safety and wondering whether my reasoning is correct. And if so, if there a better solution than the macro above?