C++11基于范围的循环:它是如何工作的?

12

我知道这个循环的工作原理,以及如何在实际问题中使用它。但我想知道在幕后发生了什么。

我认为这个循环类似于常规的for循环,例如

for(int i = 0 ; i < 5 ; i ++){
    // instructions
}

变量i只被初始化一次,所以我认为这对于基于范围的循环也是一样的。但是如果我编写以下代码:

for(const int x : vec) {
    cout << x << endl;
}

编译器允许我这样做,但我不明白为什么会这样。如果变量 x 是 const,为什么每次迭代的 x 值都不同?
编译器允许这样做,但我不明白为什么可能发生。如果变量 x 是 const,每次迭代 x 的值为何不同?

FYI,这更接近于 for (auto iter = vec.begin(); iter != vec.end(); ++iter) - AndyG
3个回答

18
循环的每次迭代都会创建一个名为x的局部变量,并将其初始化为vec的下一个元素。当循环迭代结束时,x超出了作用域。单个x永远不会被修改。

有关精确语义,请参见此链接


3

就这个问题而言,基于范围的for循环确实与传统的for循环有所不同。您提供的声明(const int x)是针对每次迭代分别声明的,与传统的for循环相比。

更准确地说:

for (const int x : vec) {
    cout << x << endl;
}

这只是一个简写形式,实际上它被替换为以下“传统迭代器循环”:

for (auto it = vec.begin(), e = vec.end(); it != e; ++it) { 
    const int x = *it; 
    cout << x << endl; 
}

(除了正文中不可用的 ite 以外;此外,vec 实际上是保存在一个单独的变量中的;但是我们不要关注这些不重要的细节;关于基于范围的 for 循环的确切定义可以在这里查找。)
请注意,在循环体内声明并初始化了 const int x,其值为 *it!因此,它在每次迭代中都被初始化,而不是被更改。

2
为了理解,你可以将编译器将for (auto x: y) {...}替换为for (auto i = begin(y), end = end(y); i != end; ++i) { auto x = *i; {...} }

对于std::vector,begin(y)/end(y) 将通过adl解析为调用y.begin()/y.end()std::begin(y)/std::end(y)版本。

大体上来说是可以理解的,但实际上语法会更加复杂。 - bolov
2
这不是很准确。想象一下ymake_temporary() - Kerrek SB
1
“i != end”,而不是“i < end”。 - T.C.
1
@leemes:在描述C++时,准确无误非常有用,因为看似不重要的细节在你最不希望出现时可能变得很重要。 - Kerrek SB

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接