C++ lambda 构造函数参数是否可以捕获构造的变量

Can a C++ lambda constructor argument capture the constructed variable?

本文关键字:变量 构造函数 lambda 参数 是否 C++      更新时间:2023-10-16

以下编译。但是,有没有任何形式的悬而未决的参考问题?

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

似乎有效。(真正的lambda当然更复杂。

但是,有没有任何形式的悬而未决的参考问题?

这完全取决于您对Foo做什么。下面是一个存在悬而未决的参考问题的示例:

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

lambda 表达式[&foo](int i){f(i, foo);}将导致编译器生成这样的闭包类(但不完全正确):

class _lambda
{
    Foo& mFoo; // foo is captured by reference
public:
    _lambda(Foo& foo) : mFoo(foo) {}
    void operator()(int i) const
    {
       f(i, mFoo);
    }
};

因此,声明Foo foo([&foo](int i){f(i, foo);});被视为Foo foo(_lambda(foo));。在这种情况下,在构造时捕获foo本身没有问题,因为这里只需要它的地址(引用通常通过指针实现)。

类型std::function<void(int)>将在内部复制构造此lambda类型,这意味着Foo的构造函数参数fn保存_lambda对象的副本(该对象包含对foo的引用(即mFoo)。

这意味着在某些情况下可能会出现悬而未决的参考问题,例如:

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.
}
相关文章: