Skip to content

Instantly share code, notes, and snippets.

@gremlinbeet
Created June 24, 2025 11:40
Show Gist options
  • Save gremlinbeet/da6fe704dfee78bc4c4a4cf2f9eac38a to your computer and use it in GitHub Desktop.
Save gremlinbeet/da6fe704dfee78bc4c4a4cf2f9eac38a to your computer and use it in GitHub Desktop.
ON_EXIT macro
//
// onexit.h
//
// Defines ON_EXIT macro to create finalizer objects.
// These objects execute specified code when they go out of scope.
//
// Useful when you can't be bothered writing RAII wrappers for every little thing in 3rd-party code,
// but still want to reduce cognitive load by not tracking stuff you might need to cleanup.
//
// Usage example:
// int my_func()
// {
// HANDLE handle = OpenHandle(...);
// ON_EXIT(CloseHandle(handle));
// void* section = BorkSection(handle);
// ON_EXIT(UnborkSection(section));
// if (bad_stuff())
// return -1; // UnborkSection(), then CloseHandle(); [same sequence in case of exception]
// ...
// }
#define ON_EXIT(...) auto CONCAT2(onExit_, __COUNTER__) = ::hax::OnExit([&]{ __VA_ARGS__; })
#define CONCAT2(a, b) CONCAT2_(a, b)
#define CONCAT2_(a, b) a ## b
namespace hax
{
template <class D> requires requires(D d) { d(); }
class OnExit
{
private:
[[msvc::no_unique_address]] // hint entire object doesn't need to take any space
D _destroyer; // normally lambda, but allowed to be ptr to function
public:
OnExit(OnExit&&) = delete; // implicitly removes all ctrs and assignments
constexpr OnExit(D destroyer): _destroyer{std::move(destroyer)} {}
constexpr ~OnExit() noexcept(noexcept(_destroyer())) { _destroyer(); }
};
} // namespace hax
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment