Ручное управление ресурсами в низкоуровневом си-подобном коде на C++ — довольно хлопотное дельце. Создание достойных RAII-врапперов для каждого используемого сишного API не всегда практично, а использование подходов с goto cleanup или множеством вложенных if (success) вредит читаемости кода.
Макрос defer, вдохновленный Go, как никогда кстати! Использовать его просто:
void* p = malloc(0x1000); defer [&] { free(p); };
Отложенная лямбда будет выполнена при выходе из области видимости, независимо от того, будет ли выполнен return, брошено исключение (если разрешено), или даже выполнен goto наружу.
Реализация макроса лаконична и полагается на базовые возможности C++17 (Clang 5+, GCC 7+, MSVC 2017+):
#ifndef defer template <typename T> struct Deferrer { T f; Deferrer(T f) : f(f) { }; Deferrer(const Deferrer&) = delete; ~Deferrer() { f(); } }; #define TOKEN_CONCAT_NX(a, b) a ## b #define TOKEN_CONCAT(a, b) TOKEN_CONCAT_NX(a, b) #define defer Deferrer TOKEN_CONCAT(__deferred, __COUNTER__) = #endif
Данный макрос по-настоящему zero-cost и не зависит от рантайма C или стандартной библиотеки, поэтому его можно использовать даже в разработке под ядро ОС.