Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scopeguard advice. #24

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ error in the function's signature. Documenting *which* exceptions can be
thrown or errors reported is not crucial, but documenting the fact
*that* an error can occur is.

<a id="reported-errors-and-class-invariants"/>
Unless otherwise specified in the function's documentation, a reported
error means all objects the function would otherwise modify are
invalid for all uses, except as the target of destruction or
Expand Down Expand Up @@ -324,6 +325,33 @@ target_link_libraries(my-executable PRIVATE adobe-contract-checks)
implementations should call the `check_invariant()`(s) of their
parent classes.

If your mutating function has multiple returns, it might be useful
to wrap your `check_invariant()` call in
[`boost::scope_success`](https://www.boost.org/doc/libs/master/libs/scope/doc/html/scope/scope_guards.html#scope.scope_guards.conditional)
(which also [may be
available](https://en.cppreference.com/w/cpp/experimental/scope_success)
in your implementation's `std::experimental` namespace), at the beginning
of the function.

```c++
void mutate_me() {
std::experimental::scope_success _([&]{ check_invariant(); });
...
}
```

**Caveats:**

1. You still need to call `check_invariant()` anywhere the object
under mutation may exposed outside the class other than by
returning, e.g. if it is passed to a callback function.

2. If your function reports errors to the caller other than by
Copy link
Member

@sean-parent sean-parent Aug 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is not true - scope_success only checks on non-exception exit (hense "success"). You might want a caveat that this does not check the invariant in case of an exception (and why) - and scope_exit can be used if the check should be done even in case of an exception.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You missed the words "other than." I'm talking about functions that e.g. return error codes.

exception (e.g. in the return value), this technique will force
your invariant to be checked even in the event of an error, which
is [inappropriate](#reported-errors-and-class-invariants), and
may force you to weaken the invariant.

- If your program needs to take emergency shutdown measures before
termination, put those in a [terminate
handler](https://en.cppreference.com/w/cpp/error/terminate_handler)
Expand Down