2

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?

Lingxi
  • 14,579
  • 2
  • 37
  • 93
  • And what if the `&&` constructor of `U` throws? Or the constructor of `T` that takes a `U` throws? If either one throws, then the move already happened and `v` has been moved-from. So no strong exception safety. – Nicol Bolas Apr 06 '18 at 03:16
  • @NicolBolas Updated question. The goal here is that so long as `T(U&&)` is exception-safe (which is the user's responsibility), the code should be exception-safe. – Lingxi Apr 06 '18 at 03:27
  • Keep in mind that `std::move` doesn't actually move anything, nor does it even compile into actual executable code. – iBug Apr 06 '18 at 03:36
  • 2
    @Lingxi: There is a difference between "exception-safe" and the "strong exception guarantee". – Nicol Bolas Apr 06 '18 at 04:04
  • What do you mean *exception-safe* there is no such word in the standard. – Yola Apr 06 '18 at 05:25

0 Answers0