Boost logo

Boost :

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


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk