通过引用传递超出范围的 lambda 是否安全?

问题描述 投票:0回答:1

周围还有类似的问题:

  • “按值”传递超出范围的 lambda 是否安全?

      是的,因为闭包被复制/移动了
  • 我应该通过 const 引用传递 lambda 吗?

    是的,这对于避免复制状态很有用。但是你不能传递一个可变的 lambda,它有一个非常量
      operator()
    • 
      
  • 我的问题是两者的混合:
有一个存储类通过引用获取 lambda 并以某种方式存储它,并使用链接问题中的方法签名:


template <class Function> void storeCallback(const Function& f)

以下方式调用安全吗?

void foo(Storage& o) { o.storeCallback([](){std::cout << "hi!";}); } void bar(Storage& o){ o.callCallback(); }

我看到的风险是,一旦 
foo

返回,lambda 就会超出范围。那么当将来某个时候调用存储的回调时,引用将无效?

在我感兴趣的特定情况下,引发了这个问题,lambda 存储在存储类中的具体情况是,它被传递到另一个方法,该方法将 

std::function

按值作为参数。这种从引用到

std::function
的转换是否以某种方式使其安全?或者无论如何存储它都已经安全了?

std::function

文档
状态

std::function
的实例可以存储、

复制

和调用任何CopyConstructible Callable目标——函数(通过指向其的指针)、
lambda表达式、绑定表达式或其他函数对象,以及指向成员函数的指针以及指向数据成员的指针。 这对我来说听起来像

std::function
使它安全,因为它无论如何都会复制 lambda,即使它是通过引用传递的。

	

在您编写的代码中,您肯定使用了某种类型擦除(如
c++ lambda
1个回答
0
投票
),因为您正在存储未知类型(lambda)。如果这个存储确实是

std::function

,那么你一定会拥有 lambda 的副本。这是因为复制到 
std::function
 会在 
foo
 超出范围之前发生。如果您的存储保存对 lambda 的引用而不是复制它,就像 
std::function_ref
 那样,这将导致未定义的行为。但请注意,由于您的 lambda 不捕获任何内容,因此即使行为实际上未定义,这也很可能会为您提供正确的结果。
另外,不要混淆通过引用捕获和通过引用传递。后者通常是安全的,前者通常不是。以这段代码片段为例:

class MyClass { void foo(Storage& o) { o.storeCallback([&]() { /* some calculation using data members */ }); } }; int main() { { MyClass obj{}; obj.foo(my_storage); } // obj goes out of scope my_storage.callCallback(); // oops! UNDEFINED BEHAVIOR return 0; }

这里,因为通过引用捕获,
this
也被捕获了!当

obj

 超出范围时,调用存储的 lambda 是未定义的行为。这就是为什么您必须非常小心地通过引用进行捕获。
	

© www.soinside.com 2019 - 2024. All rights reserved.