$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
From: Gavin Lambert (boost_at_[hidden])
Date: 2023-01-12 00:53:52
On 11/01/2023 22:35, Hans Dembinski wrote:
> Yes, FooOld2 is also unsafe, but you can use a rollback guard to undo the move.
> 
>     FooOld3(bool b, T&& targ = {}) : t_(std::move(targ)) {
>         rollback r(targ, t_); // moves t_ back to targ if not deactivated
>         if (b)
>             throw 1;
>         r.deactivate();
>     }
Note that a rollback implementation is still unsafe if the type in 
question has a noexcept(false) move constructor -- which, while unusual, 
is legal -- and might be more common than you think when it decays to 
use the copy constructor instead.  (This can also be bad for 
performance, though only when throwing, so you likely don't care.)
A common surprise is that copy-constructor-only types will still satisfy 
std::is_move_constructible_v, although typically not 
std::is_nothrow_move_constructible_v.  (Which is one of the reasons why 
the "rule of five" exists now.)
(You might ask why this is unsafe, since we only care about exceptions 
thrown in the constructor body -- if the initial parameter move/copy 
throws that's a different case, right?  But consider that the initial 
parameter move/copy might succeed, the constructor body throws, and then 
the rollback move/copy also throws.  This is especially likely if the 
constructor throw was a std::bad_alloc, but other cases are possible.)
This isn't to say that the above is bad; but if you use it, don't forget 
to static_assert your assumptions (or provide alternative implementations).