[libcxx-commits] [PATCH] D115730: [libc++] Add a helper class to write code with the strong exception guarantee
Arthur O'Dwyer via Phabricator via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Dec 14 16:54:17 PST 2021
Quuxplusone added inline comments.
================
Comment at: libcxx/test/libcxx/detail/transaction.pass.cpp:125
+ return 0;
+}
----------------
ldionne wrote:
> Quuxplusone wrote:
> > I'd also like to see that it works properly when called from a destructor. (This is more obviously a big deal for my alternative `__on_exception_rollback` design, but might as well check it no matter which design we pick.)
> > ```
> > bool rolled_back = false;
> > struct S {
> > ~S() {
> > std::__transaction t([&]{ rolled_back = true; });
> > t.__set_completed();
> > }
> > };
> > try {
> > S s;
> > throw 0;
> > } catch (...) {
> > assert(!rolled_back);
> > }
> > ```
> > (I'd say if `S` has a //data member// of type `__transaction`, that produces weird behavior but also violates the intended usage of the type, and so we shouldn't worry about //that// case.)
> Adding the test.
>
> Sorry, what does `__on_exception_rollback` do? Does it check whether the destructor is being called during stack unwinding?
Yeah, exactly what @DanielMcIntosh-IBM just said elsewhere in this review. :)
https://godbolt.org/z/78vrfj8e7
The bad thing about `uncaught_exceptions` is that compilers don't understand that its value never changes by ordinary means, so when the `__on_exception_rollback` object is destroyed in the ordinary way at the end of the scope, it causes codegen. Actually, that might make `__on_exception_rollback` a complete non-starter, unfortunately. We can't have something in a random library scope that unconditionally adds //two// calls to `std::uncaught_exceptions` on the success path. :(
However, taking another page from the `Auto.h` playbook, I think you should consider eliminating the `completed_` member altogether and just making the lambda always run on destruction. If the programmer wants the lambda's behavior to be conditional, they can just... put an `if` in it.
```
bool completed = false;
__on_scope_exit guard([&]() {
if (!completed) puts("Rolling back!");
});
puts("Starting transaction");
f();
completed = true;
// guard runs here
```
IMO, this is a more readable API than having a magic `.set_completed()` method on the guard object //itself//.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D115730/new/
https://reviews.llvm.org/D115730
More information about the libcxx-commits
mailing list