Boost logo

Boost :

From: Hans Dembinski (hans.dembinski_at_[hidden])
Date: 2023-01-11 09:35:58


>> I added FooOld, which corresponds to the unsafe design I want to replace.
>> https://godbolt.org/z/15q9EqnfP
>
> Thanks. I note that as written, FooOld actually has the same problem even
> if the argument is not taken by value.
>
> template <class T>
> struct FooOld2 {
> FooOld2(bool b, T const& targ) : t_(targ) {
> if (b)
> throw 1;
> }
> FooOld2(bool b, T&& targ = {}) : t_(std::move(targ)) {
> if (b)
> throw 1;
> }
> private:
> T t_;
> };
>
> There might be a difference between passing by value or not, but for that,
> the exception would have to be thrown from a base or previous member
> initialization, and not the constructor body.

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();
   }

Or you can put all the throwing code into a lambda

   FooOld4(bool b, T&& targ = {}) : t_(
     [&](auto&& targ) {
        // to all the potentially throwing stuff here
        return targ;
     }(std::forward(targ))
   ) {
   }

The rollback version is also ok, but cannot be used when you pass by value.

I don’t like the lambda version, it makes the code unreadable.


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