The following compiles. But is there ever any sort of dangling reference issue?
class Foo {
Foo(std::function fn) { /* etc
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.
}
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