C++11 range for 遍历多维数组, 迭代变量添加引用 "&"的问题
来源:互联网 发布:淘宝二维码生成器 编辑:程序博客网 时间:2024/04/29 12:43
问题背景
auto 是 C++ 11 扩展的新特性,用于自动类型推导。不过,如果你希望推导出的类型为引用(&),就要手动在变量名前加 '&';如果你还需要变量是常量的话,也要手动加入 'const' 修饰符。
长话短说,本篇博文的目的是,阐述 使用 ranger for 遍历多维数组时, 变量名添加引用的 '&' 的问题,解释它,本博文的参考文献[1] 《C++ Primer 5th》中虽有提及,但篇幅较小,所以在这里详细地理清思路。
引出问题
下面,用 auto 和 range for (C++ 11 扩展的遍历特性) 来遍历 二维数组 来引出问题。(range for,样式为 for ( xxxx : yyyy),是 for 循环的一种形式,本文假定你已经知道了它的用法)
给出代码如下所示:
#include <iostream>#include <cstddef>using namespace std;int main() {constexpr size_t rowCnt = 3, colCnt = 4;int arr[rowCnt][colCnt] = {};//initialized to all zero//method1 : successful compilation and iterationfor(auto &row : arr)for(auto col : row)cout << col << endl;/*//method2: compile errorfor(auto row : arr)for(auto col : row)cout << col << endl;*/return 0;}
解释
方式一
首先看外层循环语句,for (auto &row : arr) 这句话,定义了一个引用row,每次刷新(一个循环后,引用就过了生命周期,需要重新定义)迭代变量row的时 候,row都绑定 arr的一个长度为4的数组,等价于 int (&row) [4] = arr[i] (i = 0, 1, 2)。
然后 对于内层循环而言,row就是一个长度为4的一维数组的引用。
内层循环: for (auto col : row),引用 row 绑定一个 int [ ] 的一维数组,相当于就是遍历一维数组一样,没有问题。
方式二
首先看外层循环语句,for (auto row : arr),arr 的原本的类型为 int [ ] [ ],根据参考文献[1] 的说法,row 不定义为引用的时候,arr 会自动转化为 int ** 类型,而 row 作为里面的一个元素,其类型为 int *,其值正是row对应的arr中的一个元素(一个长度为4的数组)的第一个元素的指针。
那么在内层循环: for (auto col : row) 中,col 遍历的是 int *,而不是 int [ ]。而方式一的内层循环则是遍历的 int [ ]。
由此,我们发现,错误的根源很可能就在于----“遍历 type*出错,遍历 type[ ] 可以”。
写一个例子,来验证这个问题:
int list[5] = {1,2,3,4,5};//这个语句将int []转化成了 int *,并存储到了p中int *p = list;//compile error, attempting to iterate int *for(auto e : p)cout << e << " ";//correct, attempting to iterate int []for(auto e : list)cout << e << " ";
至此,我们的问题,就理解清楚了,加 & 相当于就是为了避免编译器自动把 [ ] 转换为 *。对数组类型 [ ],编译器可以确定其边界并访问,而对于指针类型 *,编译器自己是不能确定如何去遍历的,这正是 range for --- for ( xxx : yy) 形式的不足。对于普通 for,是不存在这种问题的,因为在普通 for 的指针遍历中,我们给指针初始化了开始位置,又给它指定了越界位置,而且还能选择指针的移动方式( ++、--、+=、-= ... )。因此,本篇博文,是围绕 ranger for 来进行讨论的。
使用decltype
当然啦,如果你不想用 auto 来进行自动类型推导,那么可以使用 decltype。在上面的例子中,用decltype的确不容易造成混淆,看看下面的代码,是不是很简单直接啊:
for(decltype(arr[0]) &row : arr)for(decltype(arr[0][0]) col : row)cout << col << endl;
当然,你要去掉 "&" 也是没有问题,因为decltype的类型推导自 arr[0] 和 arr[0][0],这已经是 int [ ] 和 int [ ] [ ] 了,编译器就不会把它们转化成 int * 和 int **了。
for(decltype(arr[0]) row : arr)for(decltype(arr[0][0]) col : row)cout << col << endl;
推广到更高维
如果你想用 range for 的方法,来遍历更高维的数组 (dim > 2),那么你只需要:除了最内层循环之外,其他所有外层循环都加入 '&' 即可。
References
[1] 《C++ Primer Fifth Edition》 Stanley B. Lippman, Josée Lajoie, Barbara E. Moo
- C++11 range for 遍历多维数组, 迭代变量添加引用 "&"的问题
- [C/C++]数组的引用、多维数组
- 数组的迭代遍历
- nditer —— numpy.ndarray 多维数组的迭代
- php 多维数组的遍历
- awk多维数组的遍历
- JAVA多维数组的遍历
- C程序设计基础之多维数组的指针变量
- C程序设计基础之多维数组的指针变量
- C语言入门之多维数组的指针变量
- 多维数组的指针变量
- 多维数组的指针变量
- 多维数组的指针变量
- 多维数组的指针变量
- 多维数组的问题
- go for range 遍历二维数组
- PHP的多维数组定义以及使用for循环遍历数组
- 用for循环和增强for循环遍历多维数组
- 快速体验MyCAT
- java 下执行mysql 批量插入
- h264基础概念
- windows连接代理服务器,总是弹出输入用户名和密码的框的问题
- 内存对齐以及如何关闭内存对齐
- C++11 range for 遍历多维数组, 迭代变量添加引用 "&"的问题
- 感情宣泄
- 黑马程序员—网络编程
- C#中的线程(一)入门
- BadUsb----结合实例谈此类外设的风险
- 对于ASP下的分页问题
- 时间没有动,我们在流逝。今天又是崭新的一天了,无论如何告诉自己,我太喜欢上班了,我太喜欢上学了。为了最爱的人最爱的事奋斗吧么么哒!!!
- 计算机图形学——基于3D游戏开发技术——第一章游戏模型
- 【bzoj3611】【大工程】【虚树+dp】