只读范围基于

Read-only ranged based for

让我们考虑下面的例子(当然这应该被替换为std::accumulate):

#include <vector>

auto sum(std::vector<int> const& numbers) -> int
{
    auto sum = 0;
    for(auto /*const, const&, &&, [nothing]*/ i : numbers) { sum += i; }
    return sum;
}

如您所见,有许多不同的方法可以将基于范围的 for 循环用于小型类型。 请注意,所有这些变体都使用 gcc.

在编译器资源管理器中编译为相同的汇编代码

我经常看到建议在第一种情况下使用auto i,在第二种情况下使用auto const& i

但我们是在与编译器对话,而不是这里的人。有趣的信息是变量只是输入。这不是用auto i.

表示的

那么在您只需要读取输入的任何情况下使用 auto const& i 而不是 auto i 是否有任何性能缺点?

新的循环风格看起来很简单,但也有一些陷阱需要避免,就像 C++ 中无处不在:

您有四种声明循环变量的方法可供选择:

auto i

创建项目的可写副本。对该项目的写入将丢失,因为它只是一个副本,而不是原始项目。始终避免使用此版本!

auto const i

创建只读副本。复制复杂类型的成本可能很高,因此也请避免这种情况

auto &i

创建可写引用。仅当您要修改项目时才使用此版本。

auto const& i

创建项目的只读引用。当项目没有被修改时,总是使用这个。这是最常见的形式,请习惯。

不要想太多。在 C 和 C++ 中,存在“AS IF RULE”,这会导致您的示例的任何版本都不会导致生成的机器代码发生任何变化。

看这个神马:https://godbolt.org/z/3rnWrr 解释:注意每个编译器命令行参数都在定义 VERSION 宏,以提供 autoauto&auto const & .

所以基本上,如果 vector 包含简单类型(如内置),只需使用 auto,因为它更方便。在其他复杂类型的情况下,您需要多考虑一下并在 autoauto& 之间做出决定。如果有疑问,请进行一些测量或检查装配。

很可能,在上面的示例中使用 auto const& i 而不是 auto i 没有性能劣势。在类型是相对较小的类型的情况下,编译器可能能够优化引用。

编译两个版本时,您可以检查生成的代码,看看编译器是否生成了相同的代码。然后你就知道你的编译器做了什么

另见 Will a good C++ compiler optimize a reference away?