// // 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 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