【问题标题】:Why would one ever use lambda beyond the declaring scope or functions called from the declaring scope?为什么要在声明范围之外使用 lambda 或从声明范围调用的函数?
【发布时间】:2016-05-10 06:30:53
【问题描述】:

有几种方法可以将可调用对象作为参数传递或存储它们以备将来使用。您可以使用operator() 创建一个类,您可以定义一个函数并传递一个指向它的指针,并且从 C++11 开始,您可以通过[](){} 语法定义一个 lambda。

我很欣赏 lambda 语法作为表达式中的快捷方式,例如 find_if,它经常要求一个紧凑的可调用表达式。我对 lambda 的不理解是希望在声明之外使用它们,并有可能引入悬空引用等。 C++ 已经有一种强大的方法来传递可调用对象,它比 lambda 更安全,在这种情况下,lambda 的紧凑表达式没有任何好处。

因此问题是:为什么 C++11 允许在声明 is 的函数或从中调用的函数之外使用 lambda(因此引入了悬空引用等风险)?你能举一个例子,让 lambda 保持在声明函数之外是可取的吗?

【问题讨论】:

  • 如果 lambdas 不可复制,您将无法将它们与 find_if 一起使用
  • 故事有两个方面——首先是为什么 C++ 允许它们是可复制的——这只是为了将它们传递给算法,算法通过值接受它们的参数。另一个问题是为什么有些人滥用它并真正制作长期存在的 lambdas 副本。我不知道。
  • @SergeyA 为回调存储一个长期存在的 lambda 副本对我来说似乎很好。你认为滥用 lambdas 吗?
  • @Praetorian:更改标题以澄清。
  • @Michael 您认为安全的替代方案是什么?您提到了一个传递可调用对象的强大功能。你指的是什么?

标签: c++ c++11 lambda language-lawyer


【解决方案1】:

考虑一个注册为在未来事件发生时调用的函数。将其定义为 lambda 会很方便,但它必须超出定义的范围:

例如

m_button->setOnClick(YOUR LAMBDA GOES HERE);

【讨论】:

    【解决方案2】:

    我对 lambda 的不理解是希望在声明之外使用它们,并冒着引入悬空引用等的风险。 C++ 已经有一种强大的方法来传递可调用对象,它比 lambda 更安全,在这种情况下,lambda 的紧凑表达式没有任何好处。

    (1) Lambda 的安全性并不低于任何其他定义函数对象的方式。传递 lambda 的方式与传递命名函子的实例完全相同。

    您可以将引用存储在命名仿函数中,也可以在 lambda 中捕获引用。如果函数对象超出绑定这些引用的范围,那么在任何一种情况下存储对本地对象的引用都是一个严重的错误。

    lambda 的语法是否有益,是一个偏好问题。我想,有人可能会争辩说,因为 lambdas 使函子的定义更简单,它也使损坏的函子的定义更简单。

    为什么 C++11 允许在声明 is 的函数或从中调用的函数之外使用 lambda(因此会引入悬空引用等风险)?

    首先,我认为这种语义限制很难实现。你不能让它们不可复制,因为那会使它们在标准算法中毫无用处。

    其次,因为存储函数对象以供以后使用很有用,请参阅 (2),并且使用 lambda 并不比使用命名仿函数的实例更危险,请参阅 (1)。

    您能否举个例子,让 lambda 保持在声明函数之外是可取的?

    (2) 几乎所有异步回调情况。 std::asyncstd::thread、GUI等事件系统。可调用函数对象将被存储以供以后在这些情况下使用,并且通常这些对象确实比它们创建的范围更长。

    一般而言,在这种情况下,lambdas 优于命名仿函数类型的优势在于您可以将函数定义放在使用它的正确位置。好吧,你永远无法定义它在异步回调的一般情况下实际使用的定义,但注册回调的意义就在你能得到的范围内。

    lambdas 的缺点是它们难以为人类解析的语法是不同括号、大括号和圆括号的爆炸式增长。同样,这是偏好问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-06-08
      • 2021-07-27
      • 2010-09-18
      • 1970-01-01
      • 2011-06-12
      相关资源
      最近更新 更多