Variable getting destroyed before calling lambda

669 views Asked by At

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;
    };
};
1

There are 1 answers

1
T.C. On BEST ANSWER

The lambda returned by a call to lambdaFactory captures nestedFunc by reference, but nestedFunc is a function argument passed by value, so it goes out of scope as soon as the call to lambdaFactory returns, resulting in a dangling reference.

And is there any reason for this program not crashing using Apple's LLVM ?

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.