I'm trying to build a lambda that wraps some input functions with some pre/post actions.
- My code works fine and pre/post actions get called correctly if I try to wrap a regular function/lambda.
- However, when I try to apply my decorating lambda to a function that it produced before, my program crashes after complaining that the inner function was freed at some point (this is confirmed by valgrind).
What puzzles me is that the crash depends on the compiler: the code works perfectly fine with Xcode 6 clang
(clang-3.6
based), but crashes on linux using clang++-3.6
and g++4.8.4
.
I've made a small program that reproduces the behaviour:
#include <iostream>
#include <string>
#include <functional>
using namespace std;
typedef function<void(void)> NestedFn;
int main()
{
// Create a cfunction
auto lambdaFactory = [&](string title, NestedFn nestedFunc)
{
// title is copied to the new lambda
return [&, title]() {
cerr << "------------ START -----------" << endl;
cerr << "Inside: " << title << endl;
nestedFunc();
cerr << "------------- END ------------" << endl;
};
}
auto l1 = lambdaFactory("1", []() { cerr << "\tNest (1)" << endl; });
auto l2 = lambdaFactory("2", []() { cerr << "\tNest (2)" << endl; });
l1(); // Works ok, displays, START, 1, END
l2(); // Same here
auto dobble = lambdaFactory("Dobble", l1);
dobble(); // Display START, Inside Dobble, START,
// then crashes when trying to execute nestedFunc(), ie l1()
}
What did I get wrong in the variable scope management ? And is there any reason for this program not crashing using Apple's LLVM ?
EDIT
For the record, here is the correct lambdaFactory
after the correction suggested by T.C. :
auto lambdaFactory = [&](string title, NestedFn nestedFunc)
{
return [&, title, nestedFunc]() {
cerr << "------------ START -----------" << endl;
cerr << "Inside: " << title << endl;
nestedFunc();
cerr << "------------- END ------------" << endl;
};
};
The lambda returned by a call to
lambdaFactory
capturesnestedFunc
by reference, butnestedFunc
is a function argument passed by value, so it goes out of scope as soon as the call tolambdaFactory
returns, resulting in a dangling reference.Undefined behavior is undefined. You are also likely using two different standard library implementations (libc++ on Mac/libstdc++ on linux), so there are likely differences in how everything is laid out etc.