C++ lambda 构造函数参数可以捕获构造变量吗?
Can a C++ lambda constructor argument capture the constructed variable?
以下编译。但是有没有任何悬而未决的参考问题?
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当然更复杂。)
But is there ever any sort of dangling reference issue?
这完全取决于您使用 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 像这样(但不完全正确):
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
对象的副本(持有引用(即 mFoo ) 到你的 foo
).
这意味着在某些情况下可能会出现悬挂引用问题,例如:
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.
}
以下编译。但是有没有任何悬而未决的参考问题?
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当然更复杂。)
But is there ever any sort of dangling reference issue?
这完全取决于您使用 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 像这样(但不完全正确):
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
对象的副本(持有引用(即 mFoo ) 到你的 foo
).
这意味着在某些情况下可能会出现悬挂引用问题,例如:
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.
}