指向lambda的指针指向目标的生命周期是多少?

Sub*_*ent 12 c++ lambda language-lawyer

对不起,这是一个冗长的问题,但让我分解一下:

C++标准是否保证:

void (*Ptr)(void) = [] {};
return Ptr;
Run Code Online (Sandbox Code Playgroud)

还会定义行为吗?

我理解,对于一个闭包,它将被定义,因为闭包对象是按值移动/复制的; 但是,虽然我知道'常规'函数具有无限/无生命,但Ptr的目标是否具有相同的?或者它是否被lambda的每个实例化破坏并重新创建?

我关心的原因是,如果不是,我不能使用lambdas作为回调.我想知道.

Nic*_*las 5

物体有生命; 功能没有.功能不存在或死亡; 他们总是存在.因此,函数不能"超出范围",先前有效的函数指针所指向的函数也不会消失.无论它们来自何处,函数指针始终有效.

现在,这忽略了动态加载等等,但这是超标准的行为.

从lambda返回的函数指针是一个函数指针.这不是特别的或神奇的.因此,它与任何其他函数指针的行为没有区别.


是否有可能转换为void(*)()的结果指向调用绑定到某个对象的成员函数的东西?

这是一个更复杂的问题.标准似乎相当不明确的一个.标准只说:

函数的地址,在调用时,与调用闭包类型的函数调用操作符具有相同的效果.

"同样的效果"究竟意味着什么.有人可能会争辩说"相同的效果"意味着执行函数调用操作符所执行的操作,执行相同的语句序列.人们还可以争辩说"相同的效果"意味着调用闭包对象本身.

后一种情况可能听起来很难实现,但请记住,可以使用编译器魔法.闭包可以返回一个特定于实例的函数指针,由请求时由闭包分配.或者某些人.

关于这个问题,非规范性案文似乎不是很明确.有一个(通用)lambda的闭包的例子,它说:

template<class T> auto operator()(T t) const { ... }
template<class T> static auto lambda_call_operator_invoker(T a) {
// forwards execution to operator()(a) and therefore has
// the same return type deduced
...
}
Run Code Online (Sandbox Code Playgroud)

有问题的评论建议转发,但这需要静态调用构造一个新的lambda实例来进行转发.

总的来说,标准没有明确说明在关闭破坏之后调用生成的函数指针是否合法.

  • @MM:指向成员的指针是一种不同的东西(并且是偏离主题的),但它们仍然遵循相同的想法."成员"不是对象.因此,他们没有生命.成员指针始终有效.但是,您仍然需要一个对象来调用它们; 该对象可能有效,也可能无效. (2认同)
  • 成员函数本质上是带有额外隐藏参数(this)的普通函数。因此,一旦加载了程序,所有成员函数都就位了,但还没有对象 (2认同)

use*_*253 2

lambda 函数只是实函数或函子(即具有operator()某些成员的对象,通常在构造时定义)的语法糖。因此,这样的函数或方法是在编译期间静态定义的。

尽管标准可能没有完全指定确切的实现方式,正如 @NicolBolas 指出的那样,但实际的实现似乎遵循严格的准则:没有上下文的 lambda 可以转换为普通函数指针,不会创建中间对象,也不会创建中间对象。 lambda 定义的位置,也不是调用的位置。我刚刚(再次)检查了 gcc 和 clang,我几乎确信 MSVC 也会做同样的事情。

注意:剩下的内容是关于带有上下文的 lambda,虽然对我来说这似乎更有趣和更实际的情况,但这个问题明确涉及无上下文的 lambda。

上下文存储在 lambda 中(想象一个带有一些有意义的参数的函子对象,在对象构造时接收)。因此,如果您将一些引用或指针传递给上下文,这些引用和指针(例如this)不会自动延长其相应实体的生命周期。这就是为什么当您将 lambda 保存在其定义范围以外的范围中时应该格外小心。

请参阅此已解决问题中与 lambda 及其上下文范围定义相关的问题示例。检查修复程序以了解如何使存储的 lambda 与上下文安全。

  • 你的第二段似乎是在谈论带有捕获的 lambda,但 OP 问题是关于无捕获的 lambda (4认同)