Skip to content

Instantly share code, notes, and snippets.

@gremlinbeet
Created June 24, 2025 11:40
Show Gist options
  • Select an option

  • Save gremlinbeet/da6fe704dfee78bc4c4a4cf2f9eac38a to your computer and use it in GitHub Desktop.

Select an option

Save gremlinbeet/da6fe704dfee78bc4c4a4cf2f9eac38a to your computer and use it in GitHub Desktop.

Revisions

  1. gremlinbeet created this gist Jun 24, 2025.
    40 changes: 40 additions & 0 deletions onexit.h
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,40 @@
    //
    // 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