Skip to content

Instantly share code, notes, and snippets.

@david-bakin
Last active August 6, 2022 17:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save david-bakin/f9e0ee2b8bba3db390ab6e53dc0ef6a0 to your computer and use it in GitHub Desktop.
Save david-bakin/f9e0ee2b8bba3db390ab6e53dc0ef6a0 to your computer and use it in GitHub Desktop.
O'Dwyer's Auto macro - hygenic scope guard w/ zero overhead
#pragma once
# O'Dwyer's Auto macro - hygenic scope guard w/ zero overhead
# https://quuxplusone.github.io/blog/2018/08/11/the-auto-macro/
#
# "This scope guard has perfect codegen with zero overhead (at `-O2`) on all major compilers."
# "Because it requires no explicit captures, no novel variable name, no special treatment for `this`,
# it is highly suited for mechanically generated code."
# "It is portable all the way back to C++11."
template<class L>
class AtScopeExit {
L& m_lambda;
public:
AtScopeExit(L& action) : m_lambda(action) {}
~AtScopeExit() { m_lambda(); }
};
#define TOKEN_PASTEx(x, y) x ## y
#define TOKEN_PASTE(x, y) TOKEN_PASTEx(x, y)
#define Auto_INTERNAL1(lname, aname, ...) \
auto lname = [&]() { __VA_ARGS__; }; \
AtScopeExit<decltype(lname)> aname(lname);
#define AUTO_INTERNAL2(ctr,..) \
Auto_INTERNAL1(TOKEN_PASTE(Auto_func, ctr), \
TOKEN_PASTE(Auto_instance_, ctr), __VA_ARGS__)
#define Auto(...) \
Auto_INTERNAL2(__COUNTER__, __VA_ARGS__)
# Example:
# Auto(foo->cleanup());
# Nesting example:
# Auto(
# puts("start 1");
# Auto(puts("cleanup 2"));
# puts("getting ready to clean up after 1");
# );
# "I don't always use ad-hoc scope guards, but when I do, I prefer 'auto.h'."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment