我知道之前已经有人问过很多关于这些主题的问题,但我有一个特定的情况,其中速度(适度)重要,并且使用函数指针而不是虚函数时的速度提高约为 25%。我想知道(主要出于学术原因)为什么? 为了提供更多细节,我正在编写一个由一系列单元组成的模拟。单元通过链接连接,链接决定单元之间的交互。 Link 类有一个名为 update() 的虚函数,它会导致它链接的两个 Cell 进行交互。它是虚拟的,因此我可以创建不同类型的链接来提供不同类型的交互。例如,目前我正在模拟无粘流,但我可能想要一个具有粘度或应用边界条件的链接。 实现相同效果的第二种方法是将函数指针传递给 Link 类,并使函数指针的目标成为友元。我现在可以有一个使用函数指针的非虚拟 update() 。派生类可以使用指向不同函数的指针,从而提供多态行为。
当我使用 Very Sleepy 构建两个版本和配置文件时,我发现函数指针版本明显快于虚拟函数版本,并且 Link 类似乎已完全优化 - 我只看到来 self 的调用main 函数到指向的函数。
我只是想知道是什么让我的编译器 (MSVC++ 2012 Express) 比虚函数情况更容易优化函数指针情况?
下面的一些代码如果对函数指针的情况有帮助,我相信很明显如何使用虚拟函数来完成等效操作。
void InviscidLinkUpdate( void * linkVoid )
{
InviscidLink * link=(InviscidLink*)linkVoid;
//do some stuff with the link
//e.g.
//link->param1=
}
void ViscousLinkUpdate( void * linkVoid )
{
ViscousLink * link=(ViscousLink*)linkVoid;
//do some stuff with the link
//e.g.
//link->param1=
}
class Link
{
public:
Link(Cell *cell1, Cell*cell2, float area, float timeStep, void (*updateFunc)( void * ))
:m_cell1(cell1), m_cell2(cell2), m_area(area), m_timeStep(timeStep), m_update(updateFunc)
~Link(){};
void update() {m_update( this );}
protected:
void (*const m_update)( void *, UNG_FLT );
Cell *m_cell1;
Cell *m_cell2;
float m_area;
float m_timeStep
//some other parameters I want to modify in update()
float param1;
float param2;
};
class InviscidLink : public Link
{
friend void InviscidLinkUpdate( void * linkVoid )
public:
InviscidLink(Cell *cell1, Cell*cell2, float area, float timeStep)
Link(cell1, cell2, area, timeStep, InvicedLinkUpdate)
{}
};
class ViscousLink : public Link
{
friend void ViscousLinkUpdate( void * linkVoid )
public:
ViscousLink(Cell *cell1, Cell*cell2, float area, float timeStep)
Link(cell1, cell2, area, timeStep, ViscousLinkUpdate)
{}
};
编辑
我现在已将完整源代码放在 GitHub 上 - https://github.com/philrosenberg/ung 将提交 5ca899d39aa85fa3a86091c1202b2c4cd7147287 (函数指针版本)与提交 aff249dbe5dfdbdaefc8483becef53053c4646f (虚拟函数版本)进行比较。不幸的是,我最初将测试项目基于 wxWidgets 项目,以防我想玩一些图形显示,所以如果您没有 wxWidgets,那么您需要将其破解到命令行项目中来编译它。 我使用 Very Sleepy 对其进行基准测试
进一步编辑:
milianw 关于配置文件引导优化的评论被证明是解决方案,但作为评论,我目前无法将其标记为答案。使用具有配置文件引导优化的 Visual Studio 专业版可提供与使用内联函数类似的运行时间。我猜这是 http://msdn.microsoft.com/en-us/library/e7k32f4k.aspx 中描述的虚拟调用推测。我仍然觉得有点奇怪,使用函数指针而不是虚函数可以更容易地优化这段代码,但我想这就是为什么每个人都建议进行测试,而不是假设某些代码比另一个代码更快。
最佳答案
使用函数指针与虚函数时我可以想到的两件事有所不同:
- 您的类大小会更小,因为它不会分配 vftable,因此大小更小,更适合缓存
- 使用函数指针少了一种间接(使用虚函数:对象间接、vftable 间接、虚函数间接,使用仿函数:对象间接、仿函数间接 -> 你的更新函数在编译时解析,因为它不是虚拟的)里>
关于c++ - 优化C++中的函数指针和虚函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27549402/