Это законно, чтобы new-allocate указатель на функцию?

33

Указатели на функции не являются обычными указателями данных, поскольку они не могут быть сохранены в указателе void *. Тем не менее, кажется, что я могу сохранить копию указателя функции в динамической памяти (в gcc и clang), как в коде ниже. Является ли такой код законным в соответствии со стандартом C ++, или, возможно, это своего рода расширение компилятора?

Более того, результирующий указатель на указатель на функцию ведет себя как простой указатель данных: я могу сохранить его в void * и извлечь его из void * с помощью static_cast. Это поведение гарантировано Стандартом?

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 ;

}
Адриан
источник
2
Пожалуйста, не используйте сырые указатели функций. Используйте std::functionвместо этого.
Какой-то программист чувак
Вам не нужно newбросать на void*. void* ptr = &fcnPtr;работает так же хорошо, так fcnPtrкак это объект, а не функция.
грецкий орех
5
@Someprogrammerdude std::function- это стертый контейнер для хранения произвольного вызываемого объекта, который на самом деле не является заменой для указателей на функции…
Майкл Кензел
7
(@Someprogrammerdude) Пожалуйста, не используйте вслепую / рекомендуем std::function. Он отлично подходит для хранения «полиморфных» функций (т. Е. Всего, что имеет правильную сигнатуру, даже если он содержит состояние, как в случае некоторых лямбд), но это также добавляет накладные расходы, которые могут не понадобиться. Указатель на функцию - это POD. А std::functionэто не так.
Матфея
2
@ Matthew Честно говоря, Адриан спрашивает о динамическом выделении указателя на функцию и указании на него стирания типа void*, поэтому в контексте этого вопроса, std::functionпохоже, именно то, что они искали. Я согласен с тем, что общее отклонение указателей функций SPD несостоятельно.
eerorika

Ответы:

27

Хотя указатели на функции не являются указателями на объекты, «указатель на функцию некоторого типа» все еще является типом объекта [basic.types] / 8 . Таким образом, указатели функций сами по себе являются объектами, просто на что они указывают, это не так.

Таким образом, вы можете создать объект с указателем на функцию с помощью нового выражения…

Майкл Кензел
источник
9

поскольку они (указатели на функции) не могут быть сохранены в указателе void *.

На самом деле, сохранение указателя функции как void*условно поддерживается. Это означает, что он может или не может быть сохранен в зависимости от языковой реализации. Если языковая реализация поддерживает динамическую загрузку, то, void*вероятно, поддерживается преобразование указателя функции в . GCC, Clang и MSVC поддерживают это:

reinterpret_cast<void*>(&function);

Это законно, чтобы new-allocate указатель на функцию?

Конечно. Все указатели, включая указатели функций, являются объектами, и все объекты могут быть размещены динамически.

Кроме того, результирующий указатель на функцию-указатель ведет себя как простой указатель данных

Указатель на функцию является объектом. Указатель на указатель на функцию не только «ведет себя как», но и является указателем на объект.

Я могу сохранить его в void * и извлечь его из void * с помощью static_cast. Это поведение гарантировано Стандартом?

Преобразование между указателем на void и указателем на объект разрешено, да. И преобразование туда-обратно гарантированно даст оригинальный указатель.

eerorika
источник
Спасибо. Но затем, чтобы преобразовать указатель на функцию void * (или наоборот), мне нужно использовать reinterpret_cast, верно?
Адриан
1
@ Адриан Да. Я добавил пример.
eerorika
Если кто-то хочет исключение, вероятно,: модель памяти dos medium + оверлеи. Указатели функций больше, чем указатели данных в модели среднего размера, и наложения могут быть использованы для получения плагинов, если вы попытаетесь достаточно усердно.
Джошуа