我在Bjarne Stroustrup的The C ++编程语言(第4版)中找到了这段代码。
在此示例中,据我所知,我们递增x而不将v的值复制到x中。我的问题是,为什么我们引用x,而不是v?
我试图通过将问题分解并写到纸上来理解问题,简化内存中会发生什么,但我不明白。
void increment()
{
int v[]={0,1,2,3,4,5,6,7,8,9};
for(auto& x : v)
{
++x;
}
}
答案 0 :(得分:5)
这是一个很好的初学者问题。看一下range-based for loops上的cppreference。由于v
是数组类型,因此上面的代码段扩展为
{
auto && __range = v;
for (auto __begin = __range, __end = (__range + bound);
__begin != __end; ++__begin)
{
auto& x = *__begin;
++x
}
}
其中“ bound
是数组中元素的数量(如果数组的大小未知或类型不完整,则程序格式不正确)” [来自上面的链接]。
我们可以看到,这种基于范围的for循环背后的机制确保我们在此处对v
的左值引用上起作用:auto && __range = v
使用带有转发引用的类型推导,正确的事情。
简而言之,在循环中使用auto& x
部分时,您可以控制取消引用指向该范围的迭代器(*__begin
)时要初始化的内容。例如,使用auto& x
可获得范围内元素的引用(可以更改,影响范围),使用const auto& x
可获得const
限定的元素的引用。范围内的元素(您无法更改)。您可以使用auto x
获得每个元素的副本,并使用const
获得每个元素的const auto x
限定副本,但是后者几乎没有用。
答案 1 :(得分:4)
由于for
循环正在更改数组元素,因此您需要引用每个元素以增加它们。
如果您错误地拥有:
for(auto x : v)
{
++x;
}
v
中的任何内容都不会改变,因为x
是数组元素的副本。
制作:
for(auto x : &v)
{
++x;
}
之所以无法编译,是因为&v
是数组 的地址(不是数组中第一个元素的地址,v
是),并且在范围表达式中无效。
但是使用:
for(auto& x : v)
{
++x;
}
现在将x
成为对v
中元素的引用,因此可以对其进行更改。