c++ - 优化C++中的函数指针和虚函数

标签 c++ function optimization virtual

我知道之前已经有人问过很多关于这些主题的问题,但我有一个特定的情况,其中速度(适度)重要,并且使用函数指针而不是虚函数时的速度提高约为 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/

相关文章:

javascript - 如何将对象添加到数组

javascript - 你能识别这个用 javascript 编写的哈希函数吗?

c++ - 在可执行文件中禁用优化并将它们维护在静态库中

performance - 无符号 32 位整数在 SSE 中的水平最小值和位置

javascript - 缓冲区与字符串速度 : Why is String faster?

c++ - 程序无法调用专门的模板实现

c++ - 使用 PowerBuilder 10.0 错误从 DLL 调用外部函数

c++ - 单击窗口 - 然后会发生什么?

javascript - 打印数组项时显示 "undefined"

c++ - 预先计算数据与顺序处理