Wskaźniki do funkcji nie są zwykłymi wskaźnikami danych, ponieważ nie mogą być przechowywane w pustym wskaźniku *. Niemniej jednak wydaje się, że mogę przechowywać kopię wskaźnika funkcji w pamięci dynamicznej (w gcc i clang), jak w poniższym kodzie. Czy taki kod jest zgodny ze standardem C ++, a może jest to jakieś rozszerzenie kompilatora?
Ponadto wynikowy wskaźnik do wskaźnika funkcji zachowuje się jak zwykły wskaźnik danych: mogę przechowywać go w void * i odzyskać z void * przez static_cast. Czy takie zachowanie jest gwarantowane przez standard?
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 ;
}
std::function
zamiast tego.new
rzucić navoid*
.void* ptr = &fcnPtr;
działa równie dobrze, ponieważfcnPtr
jest przedmiotem, a nie funkcją.std::function
to skasowany typ kontenera do przechowywania dowolnych wywołań, w rzeczywistości nie zastępujący wskaźników funkcji ...std::function
. Jest świetny ze względu na możliwość przechowywania funkcji „polimorficznych” (tj. Cokolwiek z odpowiednią sygnaturą, nawet jeśli zawiera stan jak w przypadku niektórych lambdów), ale to także powoduje dodatkowe obciążenie, które może nie być potrzebne. Wskaźnik do funkcji to POD. Astd::function
nie jest.void*
tekstu, więc w kontekście tego pytaniastd::function
wydaje się dokładnie tym, czego szukali. Zgadzam się, że ogólne odrzucenie wskaźników funkcji przez SPD jest nieuzasadnione.Odpowiedzi:
Podczas gdy wskaźniki funkcji nie są wskaźnikami obiektowymi, „wskaźnik do funkcji jakiegoś typu” jest nadal typem obiektu [basic.types] / 8 . Tak więc wskaźniki funkcji same w sobie są obiektami, tylko tym, na co wskazują, nie jest.
Tak więc z pewnością możesz utworzyć obiekt typu wskaźnika funkcji za pomocą nowego wyrażenia…
źródło
W rzeczywistości przechowywanie wskaźnika funkcji jako
void*
warunku jest obsługiwane warunkowo. Oznacza to, że albo może, albo nie może być przechowywany w zależności od implementacji języka. Jeśli implementacja języka obsługuje ładowanie dynamiczne,void*
prawdopodobnie obsługiwany jest wskaźnik konwersji funkcji . GCC, Clang i MSVC obsługują to:Pewnie. Wszystkie wskaźniki, w tym wskaźniki funkcji, są obiektami i wszystkie obiekty mogą być przydzielane dynamicznie.
Wskaźnik funkcji jest obiektem. Wskaźnik do wskaźnika funkcji nie tylko „zachowuje się jak”, ale jest wskaźnikiem do obiektu.
Konwersja między wskaźnikiem na pustkę i wskaźnikiem na obiekt jest dozwolona, tak. A konwersja w obie strony gwarantuje uzyskanie oryginalnego wskaźnika.
źródło