【发布时间】:2019-05-05 07:39:27
【问题描述】:
我遇到了这个关于如何使用“final”关键字来减少虚拟方法开销的 SO 问题(Virtual function efficiency and the 'final' keyword)。基于这个答案,期望派生类指针调用标记为 final 的覆盖方法将不会面临动态调度的开销。
为了衡量这种方法的好处,我设置了一些示例类并在 Quick-Bench - Here is the link 上运行它。这里有 3 种情况:
情况 1:没有最终说明符的派生类指针:
Derived* f = new DerivedWithoutFinalSpecifier();
f->run_multiple(100); // calls an overriden method 100 times
案例 2:带有 final 说明符的基类指针:
Base* f = new DerivedWithFinalSpecifier();
f->run_multiple(100); // calls an overriden method 100 times
案例 3:带有 final 说明符的派生类指针:
Derived* f = new DerivedWithFinalSpecifier();
f->run_multiple(100); // calls an overriden method 100 times
这里的函数run_multiple如下所示:
int run_multiple(int times) specifiers {
int sum = 0;
for(int i = 0; i < times; i++) {
sum += run_once();
}
return sum;
}
我观察到的结果是:
按速度:案例 2 == 案例 3 > 案例 1
但案例 3 不应该比案例 2 快得多吗?我的实验设计或我对预期结果的假设有问题吗?
编辑:
Peter Cordes 指出了一些与此主题相关的非常有用的文章供进一步阅读:
Is final used for optimization in C++?
Why can't gcc devirtualize this function call?
LTO, Devirtualization, and Virtual Tables
【问题讨论】:
-
运行
100迭代对我来说似乎不是很多。生成随机数的速度也很慢,这很容易掩盖虚拟调度,即使它比静态调度慢,它也应该非常快。 -
Quickbench 多次运行 for 循环 AFAIK。尽管如此,这里有一个可调参数设置为 1000 迭代的 Quickbench 链接。结果还是一样:quick-bench.com/zCgn3B18JlSxBZGisEdsxUNjD7U
-
我有时会在开始测试之前生成所有随机数,然后从数组中一次取出一个(当我用完时回绕)。
-
@Galik:你想要的词是“包装”。您使用的另一个词具有非常不同的含义(和发音)。
-
:) 很公平 - 让我试试。
标签: c++ oop benchmarking