Tenho uma matriz de ponteiros de função e quero atribuir funções fictícias simples.
A primeira coisa que me veio à mente foi usar lambda. Funcionou muito bem. A única coisa que me surpreendeu foi o fato de que obtenho endereços de ponteiro diferentes quando os atribuo um por um, mas obtenho endereços idênticos quando faço isso em um loop.
#include <iostream>
int main()
{
int (*ptrArr[6])(void);
int size = sizeof(ptrArr)/sizeof(void*);
// results in three different pointer addresses
ptrArr[0] = [](){return 0;};
ptrArr[1] = [](){return 0;};
ptrArr[2] = [](){return 0;};
// results in three identical pointer addresses
for(int i = 3; i < size; i++)
{
ptrArr[i] = [](){return 0;};
}
for(int i = 0; i < 6; i++)
{
std::cout << (void*)ptrArr[i] << std::endl;
}
return 0;
}
Saída:
00E9F810
00E9F840
00E9F870
00E9F8A0
00E9F8A0
00E9F8A0
Existe uma maneira de obter diferentes instâncias das funções fictícias usando o loop?
Também tentei algumas construções usando std::function<>
, mas não consegui atribuí-lo aos ponteiros de função.
você pode usar um modelo de função para gerar várias funções exclusivas fictícias.
demonstração online
o tamanho precisa ser conhecido em tempo de compilação.
Acho que o lambda variádico é C++20, para versões inferiores use uma função livre. demo
O motivo pelo qual os ponteiros às vezes são iguais e às vezes não fica muito mais claro se você substituir as expressões lambda por funções livres:
Cada vez que você escreve a expressão,
[](){return 0;};
você cria uma nova função oculta, então para cada iteração de loop seu ponteiro de função é atribuído a essa mesma função. Mesmo se você fizer um loop sobre essa expressão lambda várias vezes, ela será definida apenas uma vez. Da mesma forma, obter o endereço defooD
repeated deve sempre dar o mesmo ponteiro, obter o endereço de one[](){return 0;}
também sempre dará o mesmo ponteiro.Um lambda cria um tipo de classe distinto com um
operator()
. Um lambda não-capturador é conversível para um ponteiro de função que invoca o mesmo código que aquele operador.No seu primeiro caso de uso, você está criando 3 instâncias lambda separadas, e elas estão permanecendo no escopo até
main()
exits. São 3 objetos separados na memória ao mesmo tempo. O compilador pode reconhecer que eles estão fazendo a mesma coisa e otimizá-los em uma única instância, mas isso é improvável. Então, você acaba vendo 3 endereços separados sendo usados.No seu segundo caso de uso, você está criando e destruindo uma única instância lambda em cada iteração de loop. Há apenas 1 objeto na memória por vez, então o compilador está livre para reutilizar a mesma memória para cada objeto.