C++基础补充(01)C++11基于范围的for循环
文章目录
- 1. 基本语法
- 1.1 decalaration
- 默认获取值
- 引用&
- 自动类型推导(auto)
- 1.2 container
- 数组
- STL容器
- 初始化列表
- 自定义类型
- 返回容器的函数
- 2. 其他示例
- 2.1 遍历数组
- 2.2 遍历vector,并修改元素
- 2.3 使用常量引用遍历,防止容器中的值被误修改
- 3. 小结
C++11 引入了基于范围的for循环,自动迭代一个范围对象中的每个元素,而无需显式地使用循环变量或索引,是一种简化数组遍历、简化容器遍历的语法糖。
语法糖,“锦上添花”的意思,并不会引入新的功能或者改变语言的核心功能,只是让代码更容易理解、编写或维护。提供简洁语法,同时不影响性能。
1. 基本语法
for(declaration : container)
{
//循环体
}
1.1 decalaration
默认获取值
是一个变量,依次获取范围中的每个元素的值,即遍历过程中每个元素将自己拷贝一份给decalaration
,适合用于小型元素,例如 int
等,对于较大较复杂的对象,会有资源开销。
例如:
for(int val:vec)
{
// val 是 vec 中元素的副本
}
引用&
可以通过引用&
获取范围中的每个元素,避免复制,适用于较大的数据类型,例如:
for(string& str : vec)
{
// 遍历过程中,str 是 vec 中元素的引用
}
自动类型推导(auto)
通过auto
关键字,让编译器自动推导元素的类型。配合引用&
,可以自动处理复杂类型的推导。例如:
for(auto& elem: vec)
{
// auto& 推导出 vec 中元素的类型,通过引用获取元素
}
1.2 container
container,是被遍历的范围对象,必须支持支持begin() 和end()函数,这样才能让 for 循环知道从哪里开始和结束遍历。常见的范围对象有数组、STL容器、初始化列表,或者返回类型为容器的函数。
数组
int arr[] = {1,2,3,4,5};
for(int val:arr)
{cout<<val<<" ";
}
STL容器
例如 std::vector、std::list、std::map 等标准容器
#include <iostream>
#include <vector>
using namespace std;int main()
{vector<int>vec = { 1,2,3,4,5 };for (int i : vec){cout << i << " ";}cout << endl;return 0;
}
//输出1 2 3 4 5
初始化列表
int main()
{for (int i : { 1, 2, 3, 4, 5 }){cout << i << " ";}cout << endl;return 0;
}
//输出1 2 3 4 5
自定义类型
只要自定义类型提供了begin()和end()
函数,就可以被基于范围的for
循环遍历。例如:
class CustomContainer
{
public:int* begin() { return &data[0]; }int* end() { return &data[sizeof(data)/sizeof(data[0])]; }// 计算的是数组的长度(即 10)
private:int data[10] = { 1,2,3,4,5 };// 数组自动填充剩余部分为0
};
int main()
{CustomContainer c;for (auto i : c)cout << i << " ";// 输出 1 2 3 4 5 0 0 0 0 0return 0;
}
在C++容器(如数组、vector)等中,end()返回的不是最后一个元素的迭代器,而是指向最后一个元素下一个位置的迭代器,这个位置不是有效的元素,仅仅用于表达结束和终点。
这是C++标准库设计的常见模式,称为半开区间。范围的起点是包含的,而终点是不包含的,包含begin()所指向的元素,不包含end()所指向的位置上的元素。
返回容器的函数
如果一个函数返回容器或可迭代对象,可以直接将函数调用作为范围对象是用。例如
#include <iostream>
#include <vector>
using namespace std;vector<int> getNumbers()
{return { 1,2,3,4,5,6 };
}
int main()
{ for(int i:getNumbers())cout << i << " ";// 输出 1 2 3 4 5 6return 0;
}
2. 其他示例
2.1 遍历数组
int main()
{int arr[] = { 1,2,3,4,5,6,7,8,9,10 };for(int i:arr)cout << i <<" "; //输出1 2 3 4 5 6 7 8 9 10return 0;
}
2.2 遍历vector,并修改元素
#include <iostream>
#include <vector>
using namespace std;int main()
{vector<int> vec = { 1,2,3,4,5,6 };for (int& i : vec){i *= 2;}for (int i : vec)cout << i << " "; //输出2 4 6 8 10 12return 0;
}
2.3 使用常量引用遍历,防止容器中的值被误修改
#include <iostream>
#include <vector>
using namespace std;int main()
{vector<string> words = { "Hello","World" };for (const auto& w : words){cout << w << " ";//输出:Hello World}return 0;
}
3. 小结
基于范围的 for 循环背后的实现依赖于两个函数:
begin():指向容器或数组的第一个元素
end():指向容器或数组的末尾元素(不含)
假设我们有如下代码:
#include <iostream>
#include <vector>
#include <string>
using namespace std;int main()
{vector<string> words = { "Hello","World","C++" };for (auto& w : words){cout<<w<<" ";}cout << endl; return 0;
}
等价于
#include <iostream>
#include <vector>
#include <string>
using namespace std;int main()
{vector<string> words = { "Hello","World","C++" };for (auto w = words.begin(); w != words.end(); w++){cout << *w << " ";}cout << endl;return 0;
}