Very interesting article, especially the t_scope allocator - I never knew you could get GCC to perform that cleanup automagically. One minor grammar point: isn't a lock under contention a contended lock, not a contented lock?
This is more like Go's defer, and is far more appropriate for my use cases.
For example:
#include <vector>
#include <iostream>
class Scope {
private:
typedef std::vector<void (*)()> FV;
FV fv;
public:
void on_return(void (* f)()) {
fv.push_back(f);
}
~Scope() {
for (FV::iterator it = fv.begin(); it != fv.end(); ++it) {
(*it)();
}
}
};
void foo() {
std::cout << "Hello ";
}
void bar() {
std::cout << "World" << std::endl;
}
int main() {
Scope scope;
scope.on_return(foo);
scope.on_return(bar);
std::cout << "Hi" << std::endl;
}
With C++11 lambda syntax you can do quite a bit better.Expanding that into something providing at least most of what Go's "defer" does shouldn't be too hard.
I would still prefer a C extension... Perhaps I should just use Go these days, though ironically all these memory allocation policies are useless in a GC language.
#include <cstdio>
template <typename tFunc>
class ScopeFunc {
private:
tFunc mFunc;
public:
ScopeFunc(tFunc func) : mFunc(func) {}
~ScopeFunc() {
mFunc();
}
};
template <typename tFunc>
ScopeFunc<tFunc> on_return(tFunc func)
{
return ScopeFunc<tFunc>(func);
}
int main() {
auto first = on_return([]() { std::puts("first"); });
auto second = on_return([]() { std::puts("second"); });
std::puts("Hello");
}
Note that this is C++11, using lambdas. Also that the output will be reversed from your expectation since it's a lifo, but that's probably actually what you want for real deferred behaviour and not text output.It also optimizes nicely, which yours may not because the loop unrolling may be complicated and there's a higher chance of aliasing of the function pointers in the vector:
0000000000400600 <main>:
400600: 53 push %rbx
400601: bf e4 07 40 00 mov $0x4007e4,%edi
400606: e8 b5 ff ff ff callq 4005c0 <puts@plt>
40060b: bf ea 07 40 00 mov $0x4007ea,%edi
400610: e8 ab ff ff ff callq 4005c0 <puts@plt>
400615: bf f1 07 40 00 mov $0x4007f1,%edi
40061a: e8 a1 ff ff ff callq 4005c0 <puts@plt>
40061f: 31 c0 xor %eax,%eax
400621: 5b pop %rbx
400622: c3 retq