empo de vida de objetos lambda em relação à conversão de ponteiro de funç
Segueesta resposta Agora estou imaginando quais são as regras para a vida útil das lambdas e como elas se relacionam com a vida útil dos ponteiros de função criados pela conversão automática. Existem várias perguntas sobre a vida útil das lambdas (por exemplo,aqu eaqu), caso em que as respostas são "elas se comportam exatamente como você escreveu o objeto functor completo", no entanto, nenhuma delas aborda a conversão em ponteiro de função, o que pode ser sensivelmente um caso especia
Eu montei este pequeno exemplo de trabalho que ilustra minha preocupação:
#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;
}
Isso está bem definido para os dois casos? Ou apenas pararetFun1()
? A questão é: "é a função que o ponteiro da função aponta para chamar o próprio objeto functor ou reimplementar o corpo em uma função separada?" Qualquer um deles faria sentido, mas o fato de a conversão em ponteiro de função exigir especificamente um lambda sem captura sugere que ele pode realmente ser o últim
Colocar outra maneira - eu posso ver pelo menos duas maneiras sensatas de um compilador querer implementar essas lambdas. Uma possível implementação legal pode ser para um compilador sintetizar código como:
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;
}
nesse caso, ambos osstatic
e nãostatic
variantes deretFun
seria ótimo. Se, no entanto, também é legal para um compilador implementar o lambda como:
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;
}
entãoretFun2()
é um comportamento indefinido.