基于C ++ 11范围的循环:按值或引用const获取项目

阅读一些基于范围的循环的例子,他们提出了两种主要的方法1,2,3,4

std::vector<MyClass> vec; for (auto &x : vec) { // x is a reference to an item of vec // We can change vec's items by changing x } 

要么

 for (auto x : vec) { // Value of x is copied from an item of vec // We can not change vec's items by changing x } 

好。

当我们不需要更改vec项目时,IMO示例build议使用第二个版本(按值)。 为什么他们不提出一些const参考(至less我还没有find任何直接的build议):

 for (auto const &x : vec) // <-- see const keyword { // x is a reference to an const item of vec // We can not change vec's items by changing x } 

不好吗? 它不是避免每个迭代中的冗余副本,而它是一个const

如果您不想更改项目以及想要避免复制,那么auto const &是正确的select:

 for (auto const &x : vec) 

谁build议你使用auto &是错误的。 别理他们。

这里回顾一下:

  • selectauto x当你想处理副本。
  • 当您想要使用原始项目并select修改时,请selectauto &x
  • 当您想要使用原始项目时,请selectauto const &x并且不会修改它们。

如果你有一个std::vector<int>std::vector<double> ,那么使用auto (用值拷贝)代替const auto&就好了,因为复制一个int或者double是便宜的:

 for (auto x : vec) .... 

但是如果你有一个std::vector<MyClass> ,其中MyClass有一些非平凡的复制语义(例如std::string ,一些复杂的自定义类等),那么我build议使用const auto&来避免深拷贝

 for (const auto & x : vec) .... 

当我们不需要更改vec项目时,示例build议使用第一个版本。

然后他们给出了一个错误的build议。

为什么他们不build议引用的东西

因为他们提出了错误的build议:-)你提到的是正确的。 如果您只想观察一个对象,则不需要创build副本,也不需要非常量引用。

编辑:

我看到你链接的引用都提供了遍历一系列int值或其他基本数据types的例子。 在这种情况下,因为复制一个int并不昂贵,所以创build一个副本基本上等价于(如果不是更有效率),那么就有一个观察const &

但是,对于用户定义的types,通常情况并非如此。 UDT的复制可能是昂贵的,如果你没有创build副本的原因(例如修改检索的对象而不改变原来的),那么最好使用const &

我将在这里相反,并说没有必要为auto const &在基于循环范围。 告诉我,如果你认为下面的函数是愚蠢的(不是为了它的目的,而是写它的方式):

 long long SafePop(std::vector<uint32_t>& v) { auto const& cv = v; long long n = -1; if (!cv.empty()) { n = cv.back(); v.pop_back(); } return n; } 

在这里,作者已经创build了一个v的const引用,用于所有不修改v的操作。在我看来,这是愚蠢的,并且可以使用auto const &作为基于循环,而不是只是auto &