Can a C++ lambda constructor argument capture the

2019-04-21 00:43发布

问题:

The following compiles. But is there ever any sort of dangling reference issue?

    class Foo {
         Foo(std::function<void(int)> fn) { /* etc */ }
    }

    void f(int i, Foo& foo) { /* stuff with i and foo */ }

    Foo foo([&foo](int i){f(i, foo);});

Seems to work. (The real lambda is of course more complicated.)

回答1:

But is there ever any sort of dangling reference issue?

That depends entirely on what you're doing with Foo. Here's an example that would have dangling reference issues:

struct Foo {
     Foo() = default;
     Foo(std::function<void(int)> fn) : fn(fn) { }
     std::function<void(int)> fn;
}

Foo outer;
{
    Foo inner([&inner](int i){f(i, inner);});
    outer = inner;
}
outer.fn(42); // still has reference to inner, which has now been destroyed


回答2:

The lambda expression [&foo](int i){f(i, foo);} will lead compiler to generate a closure class something like this (but not totally correct) :

class _lambda
{
    Foo& mFoo; // foo is captured by reference

public:
    _lambda(Foo& foo) : mFoo(foo) {}

    void operator()(int i) const
    {
       f(i, mFoo);
    }
};

Therefore, the declaration Foo foo([&foo](int i){f(i, foo);}); is treated as Foo foo(_lambda(foo));. Capturing foo itself when constructing does not has problem in this situation because only its address is required here (References are usually implemented via pointers).

The type std::function<void(int)> will internally copy construct this lambda type, which means that Foo's constructor argument fn holds a copy of _lambda object (that holds a reference (i.e., mFoo) to your foo).

These implies that dangling reference issue may arise in some situations, for example:

std::vector<std::function<void(int)>> vfn; // assume vfn live longer than foo

class Foo {
     Foo(std::function<void(int)> fn) { vfn.push_back(fn); }
}

void f(int i, Foo& foo) { /* stuff with i and foo */ }

Foo foo([&foo](int i){f(i, foo);});

....

void ff()
{
    // assume foo is destroyed already,
    vfn.pop_back()(0); // then this passes a dangling reference to f.
}


标签: c++ c++11 lambda