【问题标题】:Using references as control variable in range-based for loops in c++在c ++中基于范围的for循环中使用引用作为控制变量
【发布时间】:2018-09-03 16:49:29
【问题描述】:

我一直在搞乱基于范围的 for 循环,比如这个:

int a[] = {1, 2, 3, 4};

for(auto i : a){
    cout << i;
}

(如果我错了,请在这里纠正我)我想i 在每次迭代开始时都分配了序列容器a 中的下一个值,例如:

i = a[0] … 迭代 1

i = a[1] … 迭代 2

i = a[9] … 迭代 10

我想问一下当循环控制变量是参考时这是如何工作的:

for(int &amp;i : a){...}

由于在初始化时未分配引用而是绑定了引用,并且绑定永远不会改变,那么i 如何在给定的迭代中通过a 保存a 的元素的值,但是当分配了引用时,除了在声明中就像分配原始变量一样。要更改我们必须使用引用的数组元素,我的问题是如何将单个引用绑定到不同的变量(即循环期间a 的元素),因为每个元素都可以在循环内使用相同的引用变量进行修改。

谢谢

【问题讨论】:

  • i 是循环内的局部变量。本质上,每次循环都会声明和初始化一个新实例。另请参阅this article - 它显示了编译器如何将 range-for 循环重写为“正常”循环。
  • @IgorTandetnik 我可能错了,但我认为基于范围的 for 循环可能类似于通常的 for 循环,它维护一个可以递增或递减的控制变量。还有你说的那个链接,例子看不懂,能不能简单解释一下,能回答就更好了。
  • 你的循环被编译器重写为for (auto iter = std::begin(a); iter != std::end(a); ++iter) { int&amp; i = *iter; ...} 在这种情况下,iter 只是int* 指针。

标签: c++ for-loop c++11


【解决方案1】:

我发现这个informative article 可以帮助你:

我认为文章中的以下引用回答了您的问题:

在基于范围的for 循环中,auto&amp; 将创建对范围内原始元素的引用(复数)。

其中还介绍了在基于范围的 for 循环中使用 auto 的不同方式。


for (auto x : range)

这将创建范围内每个元素的副本。因此,当您想要使用副本时,请使用此变体。


for (const auto x : range)

const auto 的使用可能表明您希望使用每个元素的不可变副本。


for (auto& x : range)

当您想在非泛型代码中修改范围内的元素时,请使用auto&amp;


for (const auto& x : range)

当您想要只读访问范围内的元素时使用const auto&amp;,即使在通用代码中也是如此


for (auto&& x : range)

当你想在通用代码中修改范围内的元素时,使用auto&amp;&amp;


for (const auto&& x : range)

此变体将仅绑定到右值,由于 const,您将无法修改或移动右值。这使得它几乎没有用处。因此,没有理由选择此变体而不是 const auto&amp;


for (decltype(auto) x : range) // C++14

意思是:应用自动类型推导,但使用decltype 规则。自动剥离顶级 cv 限定符和引用,decltype 保留它们。

【讨论】:

  • 我又明白了一个问题:如何声明和使用同名 x 的多个引用? (或者是在每次迭代开始时都声明了 x 并且之前的副本被销毁了)
  • 具体如何完成取决于编译器。编译器将遵循 Cpp 标准中定义的基于范围的循环规则。任何符合标准的实现都是可以接受的。
  • 但是对每个元素依次声明多个引用是真的吗?
  • 不是每个元素的多个引用,而是每次迭代中当前元素的一个引用。这就是我对文章中引用的陈述的理解。
  • 意味着每次迭代都有一个新的引用?
【解决方案2】:

简单的想法类似于 STL 迭代器。您也可以考虑类似的基于 for 循环的迭代器方法,例如

for(auto it = a.begin(); it != a.end(); it++){ .... }

现在,对于基于范围的方法,在每次迭代中,您的引用都会移动到下一个内存位置,并且对引用位置的访问可以更改您需要的任何内容。

for(int& i : a) { ... } 

i 在第一次迭代时引用内存位置 0xffffcbd0。
i 在第二次迭代时引用内存位置 0xffffcbd4。

... 等等。

尝试用&amp;i打印i的内存位置。

for(int& i : a) { 
    cout<<i<<endl;
    cout<<&i<<endl;
} 

【讨论】:

  • 但问题是引用只绑定一次,同一个引用变量如何在不同的执行点指向不同的位置。
  • @dev 每个复合语句一次。但每次进入该语句的范围时它都是绑定的。每次迭代是什么
猜你喜欢
  • 2013-01-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-19
相关资源
最近更新 更多