C++ 连续迭代器(C++20)
引言
C++20标准引入了一个新的迭代器概念——连续迭代器(Contiguous Iterator)。它是随机访问迭代器的一个更专门的类别,提供了对内存中连续存储元素的额外保证。在本文中,我们将深入探讨连续迭代器的概念、特点以及在实际开发中的应用。
什么是连续迭代器
连续迭代器是C++20中引入的新迭代器概念,是迭代器类别层次结构中最专门的一种。它们具有以下特点:
- 满足随机访问迭代器的所有要求
- 额外保证其所指向的元素在内存中是连续存储的
- 使得迭代器与指针之间的转换更加自然和安全
简单来说,如果一个容器的元素在内存中是相邻存储的(如数组、std::vector
、std::string
等),则可以提供连续迭代器来访问这些元素。
迭代器概念层次结构
在C++20中,迭代器按能力从低到高被分为以下几类:
连续迭代器位于这个层次结构的顶端,这意味着它拥有其他所有类型迭代器的全部功能,并额外具有内存连续性保证。
连续迭代器的要求
要成为一个连续迭代器,必须满足以下要求:
- 满足随机访问迭代器的所有要求
- 对于任何两个迭代器
a
和b
及其之间的距离n
,满足*(a + n) = *(std::addressof(*a) + n)
- 对于迭代器
i
和j
,如果i <= j
,则std::addressof(*i) <= std::addressof(*j)
备注
第2点本质上是说,通过迭代器算术得到的结果等同于通过原始指针算术得到的结果。第3点则确保了元素在内存中的顺序与迭代顺序一致。
支持连续迭代器的标准容器
C++20中,以下标准容器提供了符合连续迭代器要求的迭代器:
std::array
std::vector
std::string
std::string_view
std::span
(C++20新增)- 原生数组
连续迭代器的应用场景
1. 高效内存访问
由于连续迭代器保证元素在内存中连续存储,它非常适合需要高性能内存访问的场景:
#include <vector>
#include <iostream>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
// 使用连续迭代器进行访问
auto it = vec.begin();
// 可以直接获取底层指针
int* ptr = &(*it);
// 可以直接进行指针算术
for (int i = 0; i < vec.size(); ++i) {
std::cout << ptr[i] << " ";
}
// 输出: 1 2 3 4 5
return 0;
}
2. 与C风格API的无缝集成
连续迭代器非常适合与期望指向连续内存的函数(如C风格API)进行交互:
#include <vector>
#include <cstring>
#include <iostream>
void c_style_function(const int* data, size_t size) {
for (size_t i = 0; i < size; ++i) {
std::cout << data[i] << " ";
}
}
int main() {
std::vector<int> vec = {10, 20, 30, 40, 50};
// 直接将vector的数据传递给C风格函数
c_style_function(vec.data(), vec.size()); // 输出: 10 20 30 40 50
// 也可以通过迭代器
c_style_function(&(*vec.begin()), vec.size()); // 输出: 10 20 30 40 50
return 0;
}
3. 使用std::span进行连续内存视图操作
std::span
是C++20引入的一个非常有用的容器适配器,它提供了对连续存储序列的视图:
#include <span>
#include <vector>
#include <array>
#include <iostream>
// 接受任何连续存储的容器
void process(std::span<const int> data) {
for (int value : data) {
std::cout << value << " ";
}
std::cout << std::endl;
}
int main() {
// 使用vector
std::vector<int> vec = {1, 2, 3, 4, 5};
process(vec); // 输出: 1 2 3 4 5
// 使用array
std::array<int, 3> arr = {10, 20, 30};
process(arr); // 输出: 10 20 30
// 使用原生数组
int c_array[] = {100, 200, 300, 400};
process(c_array); // 输出: 100 200 300 400
// 使用部分序列
process(std::span(vec).subspan(1, 3)); // 输出: 2 3 4
return 0;
}