编译环境:VS2022/gcc最新版
结论
switch(各种可能性) 转而调用具体函数的,性能最高,因为编译器会将各函数内联在这里。关键是,编译期可能会将所有分支的共性提取到公共部分,并能省略对寄存器的保护等。
【表驱动】
对于函数指针数组,即使使用了const修饰指针值,
只要下标是非常量入参,即使在循环期间下标是固定值,
uint32_t i = 编译期不确定入参
for (int j = 0; j < 10000; ++j)
constFuncPtrArr[i].fpCall();
循环调用时,都会重新读取指针
.L11
……
call [QWORD PTR constFuncPtrArr[rbp]]
cmp ebx, 10000
jne .L11
【缓存函数指针】
uint32_t i = 编译期不确定入参
auto pf = constFuncPtrArr[i].fpCall;
for (int j = 0; j < 10000; ++j)
pf();
.L11
……
call esi
cmp ebx, 10000
jne .L11
但性能和前者一致。
###【Switch case】
然而使用
FP GetFunc(int i) {
switch (i)
{
case 0:
return &Call1;
case 1:
return &Call2;
default:
std::unreachable();
}
}
for (int j = 0; j < 10000; ++j)
GetFunc(i)();
编译出
.L11
如果是0……
{
……
}
如果是1……
{
……
}
cmp ebx, 10000
jne .L11
也就是编译器实际上把多态的所有可能性内联到这里了。
性能几乎是前两者的两倍