C++ 编译器优化是否可以在for循环';有条件吗?
我在阅读有关散列函数的文章(我是一名中级CS学生)时遇到了以下问题:C++ 编译器优化是否可以在for循环';有条件吗?,c++,compiler-optimization,C++,Compiler Optimization,我在阅读有关散列函数的文章(我是一名中级CS学生)时遇到了以下问题: int hash (const string & key, int tableSize) { int hasVal = 0; for (int i = 0; i < key.length(); i++) hashVal = 37 * hashVal + key[i]; ..... return hashVal; } int散列(常量字符串和键,int表大小){
int hash (const string & key, int tableSize) {
int hasVal = 0;
for (int i = 0; i < key.length(); i++)
hashVal = 37 * hashVal + key[i];
.....
return hashVal;
}
int散列(常量字符串和键,int表大小){
int hasVal=0;
对于(int i=0;i
我在查看这段代码时注意到,如果在for循环中而不是每次调用key.length(),则速度会更快:
int n = key.length();
for (int i = 0; i < n; i++)
int n=key.length();
对于(int i=0;i
我的问题是,既然这是一种明显的略微提高性能的方法,编译器会自动为我们这样做吗?我还不太了解编译器,但我对这个问题的答案很好奇。当编写代码以使用较少的操作时,人们经常指出,我所做的事情通常已经由编译器为我完成了,因此我在浪费时间,而是在做内联函数之类的事情。我之所以关心这个问题,是因为我正在编写一个游戏,在这个游戏中,物理处理需要高效,这样事情就不会觉得笨重了 有两个地方需要优化
if
子句有影响。可能大多数编译器将内联调用,使其与您编写的内容等效
if
相比,在cpu级别上的分支预测也会使它(实质上)更快。上的一个首要问题显示了这方面的一个很好的核心例子
我之前假设声明方法
length()const
就足够了。但它太弱了。方法仍然可以在不改变对象状态的情况下抛出随机内容。然而,我100%确信,优秀的编译器会像我描述的那样进行内省函数和方法。这是一个非常依赖于编译器的答案。唯一确定的方法是生成汇编程序,并查看它创建的内容(我建议您学习如何使用您的编译器并尝试一下,这非常有启发性*)
优化并不明显-编译器可以执行该优化,但前提是确保.length()
不会更改-即没有其他线程可以访问数据,并且它能够确定循环中没有任何内容会更改.length()
后者很容易检查,因为它是常量字符串,但前者则不然。话虽如此,我希望编译器假定它在中等优化水平下处处都是常量
*双关语;抱歉。简短的回答:有时它会 长答覆: 如果编译器可以根据循环本身确定key.length()是一个“常量”值,那么它将能够优化调用。这又取决于所用类的定义(在本例中为
string
,我们可以预期它是“编写良好的”)。它还依赖于编译器理解循环不会以改变key.length()
的方式改变key
这项工作的关键要素是函数是inline
(或者是一个模板函数,inline
需要允许它在不同的编译单元中多次包含,或者在同一个源文件中可用),并且源代码位于编译单元包含的头文件中
当然,C++标准中没有编译器编译这个的要求。每次调用函数都完全符合标准
如果它是一个纯函数,也就是说,没有副作用,那么将key.length()
移出循环是安全的。如果编译器能够检测到这一点,那么我认为它很可能会执行优化
遗憾的是,与FORTRAN不同的是,C++没有标准的方法来标记纯的东西。如果函数是inline
(或可内联),那么编译器就有了定义,并且可以自己计算出来,或者至少消除函数调用
将成员函数标记为const
可以保证它不会影响当前实例,但原则上没有理由认为key.length()
无法更改某些全局变量,因此我怀疑这本身就足够了
(有各种特定于编译器的方法来声明函数为纯函数——比如GCC和兼容编译器(Clang,Intel)中的
\uuuuu attribute\uuuuu((纯))
。也许可以尝试一下这些方法,看看它们是否有什么不同?从技术上讲,函数不必标记为内联函数即可内联,链接器可以跨编译单元进行更多优化。但是只有右标志和编译器版本,并且仍然允许不这样做。C++编译器不需要标记为“代码>内联< /代码>,编译器要将其内嵌;尽管有关键字名称,它实际上意味着一些不同的东西(允许多个定义)内联关键字或头文件的使用不再相关-删除该段落可能更有意义-它的减损比它多addsVendors还可以添加允许优化而不知道代码的属性。例如,GCC具有函数属性pure
和const
。