From 8eb3205aabb986ff26757cd54667e293f5094316 Mon Sep 17 00:00:00 2001 From: apenn-msft <62863214+apenn-msft@users.noreply.github.com> Date: Mon, 3 Feb 2025 17:24:20 -0500 Subject: [PATCH 1/4] explicitly document finally actions must be non-throwing because the gsl::final_action destructor is marked noexcept(true), the action cannot throw else the program will terminate; this nuance should be documented explicitly and (to be investigated later) ideally enforced in code. --- docs/headers.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/headers.md b/docs/headers.md index 96465a3..5d92d32 100644 --- a/docs/headers.md +++ b/docs/headers.md @@ -794,7 +794,7 @@ template class final_action { ... }; ``` -`final_action` allows you to ensure something gets run at the end of a scope. +`final_action` allows you to ensure non-throwing code is executed at the end of a scope. See [E.19: Use a final_action object to express cleanup if no suitable resource handle is available](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Re-finally) @@ -805,13 +805,13 @@ explicit final_action(const F& ff) noexcept; explicit final_action(F&& ff) noexcept; ``` -Construct an object with the action to invoke in the destructor. +Construct an object with the non-throwing action to invoke in the destructor. ```cpp ~final_action() noexcept; ``` -The destructor will call the action that was passed in the constructor. +The destructor will invoke the action that was passed in the constructor; if the action throws an exception the program will terminate. ```cpp final_action(final_action&& other) noexcept; From 5a66c65d0997e3975f893bfddf0e917a403f17cb Mon Sep 17 00:00:00 2001 From: apenn-msft <62863214+apenn-msft@users.noreply.github.com> Date: Mon, 3 Feb 2025 17:29:01 -0500 Subject: [PATCH 2/4] update comments in source --- include/gsl/util | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/gsl/util b/include/gsl/util index fb7572e..6e29894 100644 --- a/include/gsl/util +++ b/include/gsl/util @@ -69,7 +69,7 @@ namespace gsl // index type for all container indexes/subscripts/sizes using index = std::ptrdiff_t; -// final_action allows you to ensure something gets run at the end of a scope +// final_action allows you to ensure non-throwing code is executed at the end of a scope. template class final_action { From 8c165a4199aee2f300ff4b4958e4842af0043c19 Mon Sep 17 00:00:00 2001 From: apenn-msft <62863214+apenn-msft@users.noreply.github.com> Date: Mon, 3 Feb 2025 17:50:24 -0500 Subject: [PATCH 3/4] enforcement for no-throw finally actions a throwing finally action will be accepted by the compiler but result in surprise termination at runtime; enforce that actions provided to finally must be non-throwing at compile time. --- include/gsl/util | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/gsl/util b/include/gsl/util index 6e29894..597f35c 100644 --- a/include/gsl/util +++ b/include/gsl/util @@ -73,6 +73,8 @@ using index = std::ptrdiff_t; template class final_action { + static_assert(std::is_nothrow_invocable_v, "the provided action must be non-throwing"); + public: explicit final_action(const F& ff) noexcept : f{ff} { } explicit final_action(F&& ff) noexcept : f{std::move(ff)} { } From 9f1f78d68098aedbe5fc5d2bc6d0161b6f6ad4e3 Mon Sep 17 00:00:00 2001 From: apenn-msft <62863214+apenn-msft@users.noreply.github.com> Date: Mon, 3 Feb 2025 18:04:59 -0500 Subject: [PATCH 4/4] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a3ff066..4530ac7 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ dyn_array | & [**4. Utilities**][cg-utilities] | | move_owner | ☐ | A helper function that moves one `owner` to the other [byte](docs/headers.md#user-content-H-byte-byte) | ☑ | Either an alias to `std::byte` or a byte type -[final_action](docs/headers.md#user-content-H-util-final_action) | ☑ | A RAII style class that invokes a functor on its destruction +[final_action](docs/headers.md#user-content-H-util-final_action) | ☑ | A RAII style class that invokes a non-throwing functor on its destruction [finally](docs/headers.md#user-content-H-util-finally) | ☑ | A helper function instantiating [final_action](docs/headers.md#user-content-H-util-final_action) [GSL_SUPPRESS](docs/headers.md#user-content-H-assert-gsl_suppress) | ☑ | A macro that takes an argument and turns it into `[[gsl::suppress(x)]]` or `[[gsl::suppress("x")]]` [[implicit]] | ☐ | A "marker" to put on single-argument constructors to explicitly make them non-explicit