É legal alocar novamente um ponteiro para funcionar?

33

Ponteiros para funções não são ponteiros de dados simples, pois não podem ser armazenados em um ponteiro nulo *. No entanto, parece que eu posso armazenar a cópia de um ponteiro de função na memória dinâmica (no gcc e no clang) como no código abaixo. Esse código é legal de acordo com o padrão C ++, ou talvez seja algum tipo de extensão do compilador?

Além disso, o ponteiro resultante para o ponteiro de função se comporta como um ponteiro simples de dados: eu posso armazená-lo no vácuo * e recuperá-lo do vácuo * pelo static_cast. Esse comportamento é garantido pelo Padrão?

int main()
{
  extern void fcn();
  void (*fcnPtr)() = &fcn;
  void (**ptrToFcnPtr)() = nullptr;

  //Make the copy of fcnPtr on the heap:
  ptrToFcnPtr = new decltype(fcnPtr)(fcnPtr);
  //Call the pointed-to function : 
  (**ptrToFcnPtr)();

  //Save the pointer in void* :
  void *ptr = ptrToFcnPtr;
  //retrieve the original ptr: 
  auto myPtr = static_cast< void(**)() > (ptr) ; 
  //free memory:
  delete ptrToFcnPtr ;

}
Adrian
fonte
2
Por favor, não use ponteiros de função brutos. Use em std::functionvez disso.
Algum cara programador
Você não precisa usar o newelenco void*. void* ptr = &fcnPtr;funciona tão bem, já que fcnPtré um objeto, não uma função.
noz
5
@Someprogrammerdude std::functioné um contêiner apagado por tipo para armazenar uma chamada arbitrária, não é realmente um substituto para ponteiros de função ...
Michael Kenzel
7
(@Someprogrammerdude) Por favor, não use / recomende cegamente std::function. É excelente por sua capacidade de armazenar funções "polimórficas" (ou seja, qualquer coisa com a assinatura correta, mesmo que contenha estado como no caso de algumas lambdas), mas isso também adiciona sobrecarga que pode não ser necessária. Um ponteiro para uma função é POD. A std::functionnão é.
Matthew
2
@ Matthew Para ser justo, Adrian está perguntando sobre alocar dinamicamente o ponteiro para funcionar e apontá-lo com um apagamento de tipo void*, portanto, no contexto dessa pergunta, std::functionparece exatamente o que eles estavam procurando. Concordo que a dispensa geral dos indicadores de função do SPD não é doentia.
eerorika

Respostas:

27

Enquanto ponteiros de função não são ponteiros de objeto, "ponteiro para função de algum tipo" ainda é um tipo de objeto [basic.types] / 8 . Assim, os ponteiros de função são objetos em si, apenas o que eles apontam não é.

Assim, você pode criar um objeto do tipo ponteiro de função por meio de uma nova expressão…

Michael Kenzel
fonte
9

como eles (ponteiros de função) não podem ser armazenados em um ponteiro nulo *.

Na verdade, o armazenamento de um ponteiro de função como a void*é suportado condicionalmente. Isso significa que ele pode ou não ser armazenado, dependendo da implementação do idioma. Se a implementação do idioma suportar carregamento dinâmico, void*provavelmente a conversão do ponteiro de função é suportada. GCC, Clang e MSVC suportam isso:

reinterpret_cast<void*>(&function);

É legal alocar novamente um ponteiro para funcionar?

Certo. Todos os ponteiros, incluindo ponteiros de função, são objetos e todos os objetos podem ser alocados dinamicamente.

Além disso, o ponteiro resultante para o ponteiro de função se comporta como um ponteiro de dados simples

Ponteiro de função é um objeto. Ponteiro para um ponteiro de função não apenas "se comporta como", mas é um ponteiro para um objeto.

Eu posso armazená-lo no void * e recuperá-lo do void * pelo static_cast. Esse comportamento é garantido pelo Padrão?

A conversão entre ponteiro para vazio e ponteiro para objeto é permitida, sim. E a conversão de ida e volta garante o ponteiro original.

eerorika
fonte
Obrigado. Mas então, para converter o ponteiro de função em vazio * (ou o contrário), preciso usar reinterpret_cast, certo?
Adrian
11
@Adrian Sim. Eu adicionei um exemplo.
eerorika
Se alguém quiser uma exceção, provavelmente: dos modelo de memória média + sobreposições. Os ponteiros de função são maiores que os ponteiros de dados no modelo médio e as sobreposições podem ser usadas para obter plug-ins se você se esforçar o suficiente.
Joshua