我必须设计和开发一个将在实时环境中使用的 C++ 模块(它将在现代多核 PC 上运行)。当我设计它时,我创建了 C++ 接口(interface)(只有纯虚拟成员函数的类),并且我使用依赖注入(inject)以便能够使用 Google Mock Framework 对其进行测试。我知道这种方法与静态绑定(bind)相比具有运行时性能开销,但可测试性是一个重要因素。
我认为我们可以在开发期间测量执行时间,并在集成阶段运行测试以确定性能开销是否可以接受。
在过去的几天里,我收到了批评,说这种方法行不通,因为后期绑定(bind)具有不确定性。这种不确定性意味着即使我对其进行测试并测量执行时间,稍后在生产环境中执行时间可能会更长,这只是因为后期绑定(bind)(因为我使用了纯虚函数)。
据我所知这是不可能的(缓存未命中和类似情况除外)。如果您使用接口(interface),这意味着您将有一些额外的间接层,并且编译器在某些情况下无法优化(例如内联函数),但仅此而已。
所以我的问题不是性能开销,而是性能的可变性。它可以在两次执行之间变化吗?
我找不到关于此主题的任何文章或基准。找到的文章对静态和动态绑定(bind)之间的持续性能差异进行了基准测试,但现在这也不是问题。
如果您知道任何可公开访问的文章、网页、书籍、资源或任何可以提供帮助的信息,请与我分享。
谢谢!
更新: 我想把链接和文档放在我找到答案的地方:
- 虚函数调用的工作原理:Parashift C++ FAQ
- Technical Report on C++ Performance ,第 87 页:“如果可以在编译时确定对象的静态类型,则调用虚函数可能不会比调用非虚成员函数更昂贵。如果类型必须在运行时动态确定,每次调用的开销通常是固定数量的机器指令 (§5.3.3)。”
- Agnes Fog 的 Optimizing software in C++: An optimization guide for Windows, Linux and Mac platforms ,第 53 页:“调用虚拟成员函数所花费的时间比调用非虚拟成员函数所花费的时间多几个时钟周期,前提是函数调用语句始终调用相同版本的虚拟函数。”
最佳答案
国际 C++ 标准化委员会在 2005 年发布了一份 Technical Report on C++ Performance ,我认为它既可以作为该主题的文章,也可以作为基准。
简短的回答是缓存未命中会显着影响运行时间,并且在调用虚函数时(通常)会查询 vtable。
但在实践中(与正式相反)每次调用执行的机器代码的开销是固定的,因为所有现存的编译 C++ 实现都使用 vtables。您可以随心所欲地派生类,而不会影响调用开销。任何调用仍然执行 (1) 在对象中的已知位置查找 vtable 指针,(2) 在 vtable 中的已知位置查找函数地址,(3) 调用该函数,除非编译器知道函数指针可从例如较早的调用,如果有的话,只会使调用更快一点。
关于c++ - C++ 纯虚函数调用的性能可变性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20439099/