0

让我们考虑下面的例子(当然应该用 代替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

4

3 回答 3

2

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

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

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

于 2021-01-22T13:46:57.663 回答
1

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

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

另请参阅一个好的 C++ 编译器会优化引用吗?.

于 2021-01-22T14:09:54.027 回答
0

新的循环样式看起来很简单,但有一些陷阱需要避免,就像 C++ 中的所有地方一样:

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

auto i

创建项目的可写副本。对该项目的写入会丢失,因为它只是副本而不是原始项目。永远避免这个版本!

auto const i

创建只读副本。复制复杂类型的成本可能非常高,因此也要避免使用这种类型

auto &i

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

auto const& i

创建对该项目的只读引用。未修改项目时始终使用此选项。这是最常用的形式,请习惯。

于 2021-01-22T13:25:22.993 回答