|
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