Время жизни лямбда-объектов относительно преобразования указателя на функцию
Следующийэтот ответ Теперь мне интересно, каковы правила для времени жизни лямбды и как они соотносятся с временем жизни указателей на функции, которые создаются автоматическим преобразованием. Есть несколько вопросов о времени жизни лямбд (например,Вот а такжеВот), в этом случае ответы «они ведут себя точно так же, как вы сами написали полный объект функтора», однако ни один из них не обращается к преобразованию в указатель на функцию, что вполне может быть особым случаем.
Я собрал этот небольшой рабочий пример, который иллюстрирует мою озабоченность:
#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()
? Вопрос заключается в том, «является ли та функция, на которую указывает указатель функции, необходимой для вызова самого объекта функтора или для переопределения тела в отдельной функции?» Любой из них может иметь смысл, но тот факт, что преобразование в указатель на функцию, в частности, требует лямбда без захвата, наводит на мысль, что это может быть последний.
Другими словами, я вижу по крайней мере два разумных способа, которыми компилятор может захотеть реализовать такие лямбды. Одной из возможных, легальных реализаций может быть компилятор для синтеза кода, подобного следующему:
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;
}
в этом случае обаstatic
и неstatic
вариантыretFun
было бы хорошо. Однако, если для компилятора также допустимо реализовывать лямбду, например:
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()
является неопределенным поведением.