新分配一个函数指针是否合法?

33

函数指针不是普通的数据指针,不能存储在void*指针中。但是,在动态内存中似乎可以存储函数指针的副本(在gcc和clang中),就像下面的代码一样。这种代码是否符合C++标准,或者这是某种编译器扩展?

此外,函数指针的结果指针表现为普通数据指针:我可以将其存储在void *中,并通过static_cast从void*中检索它。这种行为是否由标准保证?

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 - Some programmer dude
5
@Someprogrammerdude std::function 是一种用于存储任意可调用对象的类型擦除容器,而不是函数指针的替代品... - Michael Kenzel
你并不是在动态创建一个函数,而是在动态创建一个指针。基本上这也是答案所说的,但我不确定这是否是你的误解... - 463035818_is_not_a_number
7
请不要盲目地使用/推荐std::function。它非常适合存储“多态”函数(即具有正确签名的任何内容,即使它包含状态,如某些lambda函数),但这也会增加一些不必要的开销。指向函数的指针是POD类型,而std::function则不是。 - Matthew
2
@Matthew 公平地说,Adrian 正在询问动态分配函数指针并使用类型擦除的 void* 指向它,因此在这个问题的上下文中,std::function 似乎正是他们正在寻找的。我确实同意 SPD 对函数指针的一般性否定是不合理的。 - eerorika
显示剩余4条评论
2个回答

27
尽管函数指针不是对象指针,但"某种类型的函数指针"仍然是一个对象类型[basic.types]/8。因此,函数指针本身也是对象,只是它所指向的东西不是对象。
因此,您可以通过new表达式创建函数指针类型的对象...

9
由于函数指针无法存储在void*指针中,因此需要注意。实际上,将函数指针存储为void*是有条件支持的。这意味着根据语言实现可否存储。如果语言实现支持动态加载,则可能支持将函数指针转换为void*。GCC、Clang和MSVC都支持此功能。
reinterpret_cast<void*>(&function);

对一个函数指针进行新的分配,是否合法?

当然可以。所有指针,包括函数指针,都是对象,都可以动态分配。

此外,指向函数指针的结果指针表现得像普通数据指针

函数指针是一个对象。指向函数指针的指针不仅“表现为”,而且就是一个对象指针。

我可以将其存储在void*中,并通过static_cast从void*检索它。这个行为由标准保证吗?

允许将指向void和指向对象的指针进行转换。而且往返转换保证会产生原始指针。


谢谢。但是,如果我想要将函数指针转换为void*(或者反过来),我需要使用reinterpret_cast,对吗? - Adrian
1
@Adrian 是的。我添加了一个例子。 - eerorika
如果有人想要一个例外,可能是:DOS 中等内存模型 + 叠加。在中等模型中,函数指针比数据指针更大,并且如果你足够努力,可以使用叠加来实现插件。 - Joshua

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接