【问题标题】:Read-only ranged based for只读范围基于
【发布时间】:2021-04-26 22:26:03
【问题描述】:

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

但是我们在这里与编译器而不是人类交谈。有趣的信息是变量只是输入。这不是auto i表达的。

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

【问题讨论】:

  • 请每个 stackoverflow.com 问题一个问题。您的一些问题确实是在征求意见,这不适合 stackoverflow.com。

标签: c++ ranged-loops


【解决方案1】:

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

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

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

【讨论】:

  • 为什么auto更方便?读者不知道该副本是实际需要执行计算还是只是只读的。
  • 只是个人选择。
【解决方案2】:

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

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

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

【讨论】:

    【解决方案3】:

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

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

    auto i
    

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

    auto const i
    

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

    auto &i
    

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

    auto const& i
    

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

    【讨论】:

    • 这不会回答问题(或编辑前的 4 个问题中的任何一个)。我知道这些变体在做什么,我的问题是关于其他副作用。
    • 四种方式?真的吗?我敢打赌我能做到int i
    • 还有auto&amp;&amp;
    猜你喜欢
    • 2011-07-26
    • 2010-09-08
    • 1970-01-01
    • 2012-05-29
    • 2016-10-31
    • 2011-10-11
    • 2011-09-05
    • 2019-04-18
    • 1970-01-01
    相关资源
    最近更新 更多