Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/162.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用函数指针剪切if语句是否会更有效?_C++_Performance_Function Pointers_Data Oriented Design - Fatal编程技术网

C++ 使用函数指针剪切if语句是否会更有效?

C++ 使用函数指针剪切if语句是否会更有效?,c++,performance,function-pointers,data-oriented-design,C++,Performance,Function Pointers,Data Oriented Design,因此,有一条规则试图将if语句从高重复循环中拉出: for( int i = 0 ; i < 10000 ; i++ ) { if( someModeSettingOn ) doThis( data[i] ) ; else doThat( data[i] ) ; } for(int i=0;i

因此,有一条规则试图将
if
语句从高重复循环中拉出:

for( int i = 0 ; i < 10000 ; i++ )
{
    if( someModeSettingOn )  doThis( data[i] ) ;
    else  doThat( data[i] ) ;
}
for(int i=0;i<10000;i++)
{
如果(somemodesetingon)执行此操作(数据[i]);
否则(数据[i]);
}
他们说,最好把它拆散,把if声明放在外面:

if( someModeSettingOn )
  for( int i = 0 ; i < 10000 ; i++ )
    doThis( data[i] ) ;
else
  for( int i = 0 ; i < 10000 ; i++ )
    doThat( data[i] ) ;      
if(somemodesetingon)
对于(int i=0;i<10000;i++)
doThis(数据[i]);
其他的
对于(int i=0;i<10000;i++)
doThat(数据[i]);
(如果你说“哦!不要自己优化它!编译器会做的!”)请确定优化器可能会为你做这件事。但是在(我不同意他的所有观点,例如他对虚拟函数的态度)中,Mike Acton说:“为什么让编译器猜测你知道的东西呢?对我来说,这些粘滞的东西最有意思

那么为什么不使用函数指针呢

FunctionPointer *fp ;
if( someModeSettingOn )  fp = func1 ;
else fp = func2 ;

for( int i = 0 ; i < 10000 ; i++ )
{
    fp( data[i] ) ;
}
FunctionPointer*fp;
如果(somemodesetingon)fp=func1;
else fp=func2;
对于(int i=0;i<10000;i++)
{
fp(数据[i]);
}

函数指针是否存在某种隐藏的开销?它是否与调用直接函数一样有效?

在本例中,无法确定哪种情况更快。您需要在目标平台/编译器上分析此代码以估计它

一般来说,在99%的情况下,这样的代码不需要优化。这是一个邪恶的过早优化的例子。
编写人类可读的代码,并仅在分析后需要时对其进行优化。

不确定它是否符合“隐藏”条件,但使用函数指针当然需要一个更高级别的间接寻址


编译器必须生成代码来取消对指针的引用,然后跳转到结果地址,而不是直接跳转到常量地址的代码,用于正常的函数调用。

不要猜测,测量

但是,如果我一定要猜测的话,我会说第三个变量(函数指针)将比第二个变量(
if
outer-loops)慢,我怀疑这可能会更好地利用CPU的分支预测

第一个变量可能与第二个变量等效,也可能不等效,这取决于编译器的智能程度,正如您已经指出的。

您有三种情况:

如果在循环内,函数指针在循环内,如果在循环外

在这三种方法中,没有编译器优化的情况下,第三种方法将是最好的。第一种方法在您想要运行的代码上执行条件引用,第二种方法在代码上执行指针反引用,而第三种方法只运行您想要运行的代码

如果你想自己优化,不要做函数指针版本!如果你不信任编译器进行优化,那么额外的间接操作最终可能会花费你的成本,而且在将来更容易意外中断(在我看来)

为什么要让编译器猜你知道的东西

因为您可能会为将来的维护人员复杂化代码,而不给代码的用户提供任何实质性的好处。这种变化强烈地存在过早的优化,只有在分析之后,我才会考虑除明显的(<代码>如果< /COD>内部循环)之外的任何其他事项。

如果分析表明这是一个问题,那么作为猜测,我相信将
if
从循环中拉出会比函数指针更快,因为指针可能会添加编译器无法优化的间接级别。它还将降低编译器内联任何调用的可能性


不过,我也会考虑使用一个抽象接口来代替<代码>如果在循环中。那么每个数据对象已经知道要自动做什么。

你必须测量哪个更快——但是我非常怀疑函数指针的答案会更快。rn处理器具有深度多管道。而函数指针可能会使编译器被迫执行实际的函数调用、推送寄存器等

“为什么要让编译器猜你知道的东西?”


您和编译器在编译时都知道一些事情,但处理器在运行时知道更多的事情,比如内部循环中是否有空管道。进行此类优化的日子已经不在嵌入式系统和图形着色器的范围内了。

我打赌第二个版本将是最快的版本ode>if/else在循环之外,前提是当我们在最广泛的编译器中绑定并测试此功能时,我可以获得退款。:-D我与VTune打了相当多年的赌

也就是说,如果我输了,我会很高兴。我认为现在很多编译器都可以优化第一个版本,与第二个版本相抗衡,检测到重复检查循环内没有变化的变量,从而有效地提升循环外发生的分支

然而,我还没有遇到过这样的情况,我见过优化器做类似于内联一个间接函数调用的事情……尽管如果有这样的情况,优化器可以做到这一点,你的肯定是最简单的,因为它将地址分配给要在调用这些函数的同一个函数中调用的函数如果优化器现在能做到这一点,我会非常惊喜,特别是因为从可维护性的角度来看,我最喜欢您的第三个版本(如果我们想添加导致调用不同函数的新条件,最容易更改的一个)

尽管如此,如果它无法内联,那么函数指针解决方案将有一种成本最高的趋势,这不仅是因为跳远和潜在的额外堆栈溢出等等,还因为优化器将缺少信息-