迭代 const 容器时,编译器会展开“for”循环吗?

zbh*_*047 6 c++ c++11

在 C++11 中,我们可以在迭代容器时使用更简单的“for”循环,如下所示:

for (auto i : {1, 2, 3, 4})
    ...;
Run Code Online (Sandbox Code Playgroud)

但是,我不知道此类代码的效率。具体来说:

  • {1, 2, 3, 4} 的类型是什么?它是原始数组,还是转换为其他容器,例如 std::vector?
  • 编译器会展开循环吗?

更新:假设我们使用-O2,并且循环中的代码只是几个操作。就我而言,我想枚举四个方向 UP DOWN LEFT RIGHT 并使用方向参数调用一个函数。我只关心程序是否可以具有最佳性能。

非常感谢!

eer*_*ika 8

{1, 2, 3, 4} 的类型是什么?

std::initializer_list将从该初始化程序构造。那是被迭代的。你甚至需要包括<initializer_list>它才能工作。

编译器会展开循环吗?

该语言不保证循环展开。您可以通过编译和检查生成的程序集,找出特定编译器是否使用特定目标 CPU 的特定选项展开特定循环。

这就是说,迭代的次数在编译时是已知的,并且因此可以为编译器展开整个循环。


假设我们使用 -O2

值得一提的是,-O2 不启用-funroll-loops。在添加该选项之前,请阅读其文档:

-funroll-loops

展开循环,其迭代次数可以在编译时或进入循环时确定。-funroll-loops 意味着 -frerun-cse-after-loop。此选项会使代码更大,并且可能会也可能不会使其运行得更快。

在这个例子中,Clang 确实展开了循环:https : //godbolt.org/z/enKzMh而 GCC 没有展开:https : //godbolt.org/z/ocfor8


Phi*_*ßen 5

不能保证,但编译器可以优化某些情况,因此您最终得到好的代码的可能性很高。

例如,可以完全优化掉:

#include <initializer_list>

// Type your code here, or load an example.
int sum() {
    int sum = 0;
    for (auto i : {1, 2, 3, 4}) {
        sum += i;
    }
    return sum;
}

int main() {
  return sum();
}
Run Code Online (Sandbox Code Playgroud)

https://godbolt.org/z/racnKf

用 编译-O3,gcc 可以推导出计算结果为 10:

sum():
        mov     eax, 10
        ret
main:
        mov     eax, 10
        ret
Run Code Online (Sandbox Code Playgroud)

在实际示例中,编译器可能无法对其进行优化,因此您必须自己验证。