【问题标题】:C++ iterate primitive type container with ranged forC++ 使用 ranged for 迭代原始类型容器
【发布时间】:2020-12-02 08:55:13
【问题描述】:

用 ranged for(用于读取元素值)迭代原始类型容器的更好方法(性能)是什么 - 按 ref 或按值读取元素?

std::vector<int> v;
for (const auto e : v) { std::cout << e; }

for (const auto& e : v) { std::cout << e; }

有: Is it counter-productive to pass primitive types by reference?

想知道这 2 件事(通过 ref 和 value 传递和迭代)是否有某种关联。

另一个说明: 我确实认识到通过 ref、const-ref 和 value 访问以及复制值之间有什么区别 - 我只对只读方式的性能更好感兴趣。

【问题讨论】:

  • 您可以随时查看生成的程序集。就我而言,它是一样的:godbolt.org/z/9snT1o.
  • 看起来很有趣的方法!也想过,但还没试过。
  • 如果您关心此类细节的性能,它是唯一的方法;)

标签: c++ primitive-types ranged-loops


【解决方案1】:

对于小的原始类型,如果您想要修改容器的元素,那么这确实是样式问题,尽管对于这种“只读”访问,您使用按值方法可能更安全(实际上防止对“原件”进行任何意外修改 - 尽管引用上的 const 限定符也可以防止这种情况发生)。

但是,如果您确实想要修改包含的元素,那么您将需要使用引用变量进行迭代,如下面的代码示例所示:

#include <iostream>
#include <vector>

int main()
{
    std::vector<int> v{ 1,2,3,4,5 };

    for (auto e : v) ++e;                   // By value: takes copies
    for (auto f : v) std::cout << f << " "; // Elements unchanged
    std::cout << std::endl;

    for (auto& e : v) ++e;                  // By reference: refers to actual elements
    for (auto f : v) std::cout << f << " "; // Elements incremented
    std::cout << std::endl;

//  for (const auto& e : v) ++e;            // const reference: Compiler error!

    return 0;
}

【讨论】:

  • 请注意,by-value 和 by-const-reference 之间的一个区别是,如果您尝试修改迭代值,后者会给您编译器错误,而前者不会。这可能是可取的,也可能是不可取的。
  • 请注意,OP 已编辑,现在问题在const autoconst auto&amp; 之间,即不会发生意外修改副本,尽管const auto 是我很少看到的东西
  • @largest_prime_is_463035818 球门柱移动得如此轻微 - 但至少现在我会让我的答案站得住脚。
【解决方案2】:

我并不是说这是唯一正确的方法,但它是一种完全有效的方法:编写代码时不要担心性能。关注可读性并在您有正确且有效的内容时保持性能。

以此为前提,我的建议如下:

当您不需要修改容器元素时,将其用作默认值:

for (const auto& e : v) {}

仅当由于某种原因需要元素的副本(但仍不想修改元素)时使用

void foo(int& x) {}
for (auto e : v) {
    e += 5;
    foo(e);
}

如果您需要修改元素,请使用参考:

 for (auto& e : v) {}

最后但并非最不重要的一点是,一旦您编写了正确的代码,并且通过测量您意识到这个循环是一个瓶颈:查看程序集,看看哪个更好。

但是,考虑到任何重要的循环体都可能超过复制小类型和获取引用之间的差异。

【讨论】:

    【解决方案3】:

    理论上,对象变量可能更有效,因为它不涉及通过引用进行间接访问。但是,至少在这个简单的示例中,参考版本可能会被优化为与对象版本相同,因此在实践中不一定重要。

    想知道这 2 件事(通过 ref 和 value 传递和迭代)是否可能有某种关联。

    是的。相同的经验法则适用于这两种情况。在这两种情况下,优化器是否内联所有内容都可能无关紧要。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-27
      • 2018-10-16
      • 2021-11-25
      • 1970-01-01
      • 2017-01-03
      • 2014-03-21
      相关资源
      最近更新 更多