aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/libutil/finally.hh25
1 files changed, 24 insertions, 1 deletions
diff --git a/src/libutil/finally.hh b/src/libutil/finally.hh
index f2293e5d4..cbfd6195b 100644
--- a/src/libutil/finally.hh
+++ b/src/libutil/finally.hh
@@ -1,6 +1,9 @@
#pragma once
///@file
+#include <cassert>
+#include <exception>
+
/**
* A trivial class to run a function at the end of a scope.
*/
@@ -19,5 +22,25 @@ public:
Finally(Finally &&other) : fun(std::move(other.fun)) {
other.movedFrom = true;
}
- ~Finally() noexcept(false) { if (!movedFrom) fun(); }
+ ~Finally() noexcept(false)
+ {
+ try {
+ if (!movedFrom)
+ fun();
+ } catch (...) {
+ // finally may only throw an exception if exception handling is not already
+ // in progress. if handling *is* in progress we have to return cleanly here
+ // but are still prohibited from doing so since eating the exception would,
+ // in almost all cases, mess up error handling even more. the only good way
+ // to handle this is to abort entirely and leave a message, so we'll assert
+ // (and rethrow anyway, just as a defense against possible NASSERT builds.)
+ if (std::uncaught_exceptions()) {
+ assert(false &&
+ "Finally function threw an exception during exception handling. "
+ "this is not what you want, please use some other methods (like "
+ "std::promise or async) instead.");
+ }
+ throw;
+ }
+ }
};