I've recently begun learning C++, previously I programmed in Go.
I was recently informed that I should not be using new
because exceptions thrown may cause the allocated memory not to be free
d and result in a memory leak. One popular solution to this is RAII, and I found a really good explanation of why to use RAII and what it is here.
However, coming from Go this whole RAII thing seemed unnecessarily complicated. Go has something called defer that solves this problem in a very intuitive way. You just wrap what you want to do when the scope ends in defer()
, e.g. defer(free(ptr))
or defer(close_file(f))
and it'll automagically happen at the end of the scope.
I did a search and found two sources that had attempted to implement the defer functionality in C++ here and here. Both ended up with almost exactly the same code, perhaps one of them copied the other. Here they are:
Defer implentation 1:
template <typename F>
struct privDefer {
F f;
privDefer(F f) : f(f) {}
~privDefer() { f(); }
};
template <typename F>
privDefer<F> defer_func(F f) {
return privDefer<F>(f);
}
#define DEFER_1(x, y) x##y
#define DEFER_2(x, y) DEFER_1(x, y)
#define DEFER_3(x) DEFER_2(x, __COUNTER__)
#define defer(code) auto DEFER_3(_defer_) = defer_func([&](){code;})
Defer implementation 2:
template <typename F>
struct ScopeExit {
ScopeExit(F f) : f(f) {}
~ScopeExit() { f(); }
F f;
};
template <typename F>
ScopeExit<F> MakeScopeExit(F f) {
return ScopeExit<F>(f);
};
#define SCOPE_EXIT(code) \
auto STRING_JOIN2(scope_exit_, __LINE__) = MakeScopeExit([=](){code;})
I have 2 questions:
It seems to me that this
defer
is essentially doing the same thing as RAII, but much neater and more intuitively. What is the difference, and do you see any problems with using thesedefer
implementations instead?I don't really understand what the
#define
part does on these implementations above. What is the difference between the two and is one of them more preferable?