按照这个答案,我现在想知道 lambda 生命周期的规则是什么,以及它与自动转换创建的函数指针的生命周期有何关系。关于 lambda 的生命周期有几个问题(例如here和here),在这种情况下,答案是“它们的行为与您自己编写完整的仿函数对象完全一样”,但是两者都没有解决转换为函数指针的问题,这可能是一个非常明智的特例。
我整理了这个小例子来说明我的担忧:
#include <iostream>
typedef int (*func_t)(int);
// first case
func_t retFun1() {
static auto lambda = [](int) { return 1; };
// automatically converted to func_t
return lambda;
}
// second case
func_t retFun2() {
// no static
auto lambda = [](int) { return 2; };
// automatically converted to func_t and
// the local variable lambda reaches the end of its life
return lambda;
}
int main() {
const int a = retFun1()(0);
const int b = retFun2()(0);
std::cout << a << "," << b << std::endl;
return 0;
}
这对这两种情况都有很好的定义吗?还是只为retFun1()
?问题是:“函数指针指向的函数是否需要调用函子对象本身,或者在单独的函数中重新实现主体?” 任何一个都有意义,但是转换为函数指针特别需要一个无捕获的 lambda 的事实表明它实际上可能是后者。
换句话说 - 我可以看到编译器可能希望实现此类 lambda 的至少两种合理方式。一种可能的合法实现可能是编译器合成如下代码:
func_t retFun3() {
struct __voodoo_magic_lambda_implementation {
int operator()(int) const {
return 3;
}
static int plainfunction(int) {
return 3;
}
operator func_t() const {
return plainfunction;
}
} lambda;
return lambda;
}
在这种情况下,thestatic
和非static
变体retFun
都可以。但是,如果编译器实现 lambda 也是合法的,例如:
static int __voodoo_impl_function(int x);
static struct __voodoo_maigc_impl2 {
int operator()(int) const {
return 4;
}
operator func_t() const {
return __voodoo_impl_function;
}
} *__magic_functor_ptr;
static int __voodoo_impl_function(int x) {
return (*__magic_functor_ptr)(x);
}
func_t retFun4() {
__voodoo_maigc_impl2 lambda;
// non-static, local lifetime
__magic_functor_ptr = λ //Or do the equivalent of this in the ctor
return lambda;
}
然后retFun2()
是未定义的行为。