Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/140.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++ 编译器优化是否可以在for循环';有条件吗?_C++_Compiler Optimization - Fatal编程技术网

C++ 编译器优化是否可以在for循环';有条件吗?

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表大小){

我在阅读有关散列函数的文章(我是一名中级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 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