std::span在c++++20中提供了一种更安全、更现代的方式来表示连续内存区域的视图,它通过封装指针和长度信息解决了原始指针在尺寸缺失、语义模糊、调试困难和维护成本高等问题。1. 它将数据地址与长度打包为一个类型,避免函数调用时需额外传递长度参数的风险;2. 支持从std::vector、c风格数组、std::array、裸指针及另一span构造,具备高度灵活性;3. 可创建子视图而无需复制数据,提升性能与便捷性;4. 与迭代器和范围for循环无缝集成,简化遍历操作并增强代码可读性;5. 被广泛应用于函数参数传递、统一处理不同容器、解析二进制数据、只读访问等场景,提升了接口清晰度与安全性;6. span不管理内存生命周期,开发者需自行确保底层数据的有效性,从而实现职责分离的设计理念。

std::span

std::span
int* arr
size_t size
std::span
std::span<T>

举个例子,以前你可能这么写:
立即学习“C++免费学习笔记(深入)”;
void process_data(int* data, size_t size) {
for (size_t i = 0; i < size; ++i) {
// ...
}
}
std::vector<int> vec = {1, 2, 3, 4, 5};
process_data(vec.data(), vec.size());
int arr[] = {6, 7, 8};
process_data(arr, std::size(arr)); // 或者 sizeof(arr)/sizeof(arr[0])现在有了
std::span

#include <vector>
#include <span>
#include <iostream>
void process_data_with_span(std::span<int> data_view) {
// std::span支持范围for循环,非常方便
for (int val : data_view) {
std::cout << val << " ";
}
std::cout << std::endl;
// 也可以像数组一样访问,但它本身不提供at()进行边界检查(除非你自行实现或debug模式下编译器加固)
// 不过,它的存在本身就鼓励了更安全的编程范式
if (!data_view.empty()) {
std::cout << "First element: " << data_view[0] << std::endl;
}
}
int main() {
std::vector<int> vec = {10, 20, 30, 40, 50};
process_data_with_span(vec); // 直接从vector构造span
int c_array[] = {1, 2, 3};
process_data_with_span(c_array); // 直接从C风格数组构造span
// 甚至可以从原始指针和长度构造
int* raw_ptr = new int[4]{100, 200, 300, 400};
process_data_with_span({raw_ptr, 4}); // 从指针和长度构造span
delete[] raw_ptr; // 记得释放内存,span不负责内存管理
// 还可以创建子视图
std::span<int> full_span = vec;
std::span<int> sub_span = full_span.subspan(1, 3); // 从索引1开始,长度为3
std::cout << "Sub-span: ";
process_data_with_span(sub_span); // 输出 20 30 40
return 0;
}通过
std::span
std::span
在我看来,原始数组指针在C++中一直是个“双刃剑”。它的灵活度很高,直接操作内存,性能自然没得说。但问题是,这种灵活性往往伴随着巨大的风险。最让人头疼的,莫过于“越界访问”这个顽疾。当你只拿着一个
int* p
p
int
int
int*
size_t
int*
std::span
std::span
std::span
常见构造方式:
std::vector
std::span
std::vector
std::vector<double> sensor_readings = {1.2, 3.4, 5.6};
std::span<double> view_readings = sensor_readings; // 隐式转换
// 或者 std::span<double> view_readings(sensor_readings); 显式构造int raw_data[] = {10, 20, 30, 40};
std::span<int> view_raw_data = raw_data; // 隐式转换std::array
std::array
std::span
std::array<char, 5> buffer = {'H', 'e', 'l', 'l', 'o'};
std::span<char> view_buffer = buffer;char* dynamic_buffer = new char[100]; // ... 填充数据 std::span<char> view_dynamic_buffer(dynamic_buffer, 100); delete[] dynamic_buffer; // span不拥有内存,记得释放
std::span
std::span
std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8};
std::span<int> all_numbers = numbers;
std::span<int> middle_slice = all_numbers.subspan(2, 4); // 从索引2开始,取4个元素 (3, 4, 5, 6)
std::span<int> tail_slice = all_numbers.last(3); // 最后3个元素 (6, 7, 8)实际应用场景:
std::span
std::span<T>
std::span<const T>
// 以前:void process(const int* data, size_t count); // 现在:void process(std::span<const int> data);
std::vector
std::array
std::span
std::span
std::span<const T>
std::span
std::span
std::span
std::span
首先,
std::span
begin()
end()
std::span
#include <iostream>
#include <vector>
#include <span>
void print_elements(std::span<const int> data_view) {
std::cout << "Elements: ";
for (int x : data_view) { // 直接使用范围for循环
std::cout << x << " ";
}
std::cout << std::endl;
}
int main() {
std::vector<int> my_vec = {100, 200, 300, 400, 500};
print_elements(my_vec);
int c_arr[] = {1, 2, 3};
print_elements(c_arr);
std::span<int> sub_span = my_vec;
print_elements(sub_span.subspan(1, 3)); // 对子视图也同样适用
return 0;
}这种方式比传统的
for (size_t i = 0; i < data_view.size(); ++i)
此外,
std::span
cbegin()
cend()
rbegin()
rend()
#include <iostream>
#include <vector>
#include <span>
#include <numeric> // for std::accumulate
#include <algorithm> // for std::sort
void analyze_span(std::span<int> data) {
if (data.empty()) {
std::cout << "Span is empty." << std::endl;
return;
}
// 使用std::accumulate计算和
long long sum = std::accumulate(data.begin(), data.end(), 0LL);
std::cout << "Sum: " << sum << std::endl;
// 查找最大元素
auto max_it = std::max_element(data.begin(), data.end());
if (max_it != data.end()) {
std::cout << "Max element: " << *max_it << std::endl;
}
// 对span进行排序 (注意:这会修改原始数据,因为span是非const的)
std::sort(data.begin(), data.end());
std::cout << "Sorted span: ";
for (int x : data) {
std::cout << x << " ";
}
std::cout << std::endl;
}
int main() {
std::vector<int> values = {5, 1, 9, 3, 7};
analyze_span(values); // 传递vector的span视图
int arr[] = {10, 2, 8, 4, 6};
analyze_span(arr); // 传递C风格数组的span视图
return 0;
}这里需要强调的是,
std::span
std::span<T>
std::vector
std::span
std::span
span
以上就是C++20中span如何替代原始数组指针 安全数组视图的用法的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号