还有类似的问题:
传递超出范围的“按值” lambda 是否安全?
- 是的,因为闭包被复制/移动了
-
- 是的,这对于避免复制状态很有用。但你不能传递可变的 lambda,因为它有一个非常量
operator()
- 是的,这对于避免复制状态很有用。但你不能传递可变的 lambda,因为它有一个非常量
我的问题是两者的混合:
有一个存储类,它通过引用获取 lambda 并以某种方式存储它,使用的方法签名类似于链接的问题:
template <class Function>
void storeCallback(const Function& f)
按以下方式调用是否安全?
void foo(Storage& o) {
o.storeCallback([](){std::cout << "hi!";});
}
void bar(Storage& o){
o.callCallback();
}
我看到的风险是 lambda 一旦返回就会超出范围foo
。那么将来调用存储的回调时,引用会无效吗?
在我感兴趣的特定情况下,这引发了这个问题,lambda 在存储类中存储的具体方式是,它被传递给另一个以std::function
值作为参数的方法。这种从引用到转换的方式是否以std::function
某种方式使其安全?或者它已经是安全的,与存储方式无关?
文档std::function
指出
的实例
std::function
可以存储、复制和调用任何 CopyConstructible Callable 目标——函数(通过指向其的指针)、lambda 表达式、绑定表达式或其他函数对象,以及指向成员函数的指针和指向数据成员的指针。
在我看来,这听起来很std::function
安全,因为无论如何它都会复制 lambda,即使它是通过引用传递的。
在您编写的代码中,您肯定使用了某种类型擦除(如
std::function
),因为您正在存储未知类型(lambda)。如果此存储std::function
确实是,则保证您拥有 lambda 的副本。这是因为复制到将在超出范围std::function
之前发生。如果您的存储保存了对 lambda 的引用而不是像复制它一样,这会导致未定义的行为。但请注意,由于您的 lambda 不会捕获任何内容,因此即使行为实际上是未定义的,这也可能会给您正确的结果。foo
std::function_ref
另外,不要混淆按引用捕获和按引用传递。后者通常是安全的,前者通常不安全。如果你有这个,
的引用
name
将悬空。如果您在成员函数内通过引用进行捕获,则可能会更加危险,因为您可能会意外地this
通过引用进行捕获,而这就是即将发生的 UB。