C++11 lambdas are great!
But one thing is missing, which is how to safely deal with mutable data.
The following will give bad counts after the first count:
#include <cstdio>
#include <functional>
#include <memory>
std::function<int(void)> f1()
{
int k = 121;
return std::function<int(void)>([&]{return k++;});
}
int main()
{
int j = 50;
auto g = f1();
printf("%d\n", g());
printf("%d\n", g());
printf("%d\n", g());
printf("%d\n", g());
}
gives,
$ g++-4.5 -std=c++0x -o test test.cpp && ./test
121
8365280
8365280
8365280
The reason is that after f1()
returns, k
is out of scope but still on the stack. So the first time g()
is executed k
is fine, but after that the stack is corrupted and k
loses its value.
So, the only way I've managed to make safely returnable closures in C++11 is to allocate closed variables explicitly on the heap:
std::function<int(void)> f2()
{
int k = 121;
std::shared_ptr<int> o = std::shared_ptr<int>(new int(k));
return std::function<int(void)>([=]{return (*o)++;});
}
int main()
{
int j = 50;
auto g = f2();
printf("%d\n", g());
printf("%d\n", g());
printf("%d\n", g());
printf("%d\n", g());
}
Here, [=]
is used to ensure the shared pointer is copied, not referenced, so that memory handling is done correctly: the heap-allocated copy of k
should be freed when the generated function g
goes out of scope. The result is as desired,
$ g++-4.5 -std=c++0x -o test test.cpp && ./test
121
122
123
124
It's pretty ugly to refer to variables by dereferencing them, but it should be possible to use references instead:
std::function<int(void)> f3()
{
int k = 121;
std::shared_ptr<int> o = std::shared_ptr<int>(new int(k));
int &p = *o;
return std::function<int(void)>([&]{return p++;});
}
Actually, this oddly gives me,
$ g++-4.5 -std=c++0x -o test test.cpp && ./test
0
1
2
3
Any idea why? Maybe it's not polite to take a reference of a shared pointer, now that I think about it, since it's not a tracked reference. I found that moving the reference to inside the lambda causes a crash,
std::function<int(void)> f4()
{
int k = 121;
std::shared_ptr<int> o = std::shared_ptr<int>(new int(k));
return std::function<int(void)>([&]{int &p = *o; return p++;});
}
giving,
g++-4.5 -std=c++0x -o test test.cpp && ./test
156565552
/bin/bash: line 1: 25219 Segmentation fault ./test
In any case, it would be nice if there was a way to automatically make safely returnable closures via heap allocation. For example, if there was an alternative to [=]
and [&]
that indicated that variables should be heap allocated and referenced via references to shared pointers. My initial thought when I learned about std::function
was that it creates an object encapsulating the closure, therefore it could provide storage for the closure environment, but my experiments show that this doesn't seem to help.
I think safely returnable closures in C++11 are going to be paramount to using them, does anyone know how this can be accomplished more elegantly?