避免越界需每次取std::min(i + chunk_size, vec.size())为结束位置;C++20 std::views::chunk不均分,末块≤指定值;返回vector<vector<T>>时应预分配并用emplace_back构造。

用 std::vector 手动切分数组时,如何避免越界?
直接按块大小循环取子段最常见,但容易在最后一块踩坑:当数组长度不能被块大小整除时,std::vector::subspan(C++20)或 std::vector::data() + std::vector::size() 手动计算边界时,若不检查剩余元素数量,会触发未定义行为。
正确做法是每次计算起始位置 i 后,取 std::min(i + chunk_size, static_cast<int>(vec.size()))</int> 为结束位置:
std::vector<int> arr = {1,2,3,4,5,6,7};
int chunk_size = 3;
for (int i = 0; i < arr.size(); i += chunk_size) {
int end = std::min(i + chunk_size, static_cast<int>(arr.size()));
std::vector<int> chunk(arr.begin() + i, arr.begin() + end);
// 处理 chunk
}
C++20 的 std::ranges::chunk_view 能否真正“均分”?
不能。它只是把连续迭代器按固定长度“切片”,最后一块大小一定 ≤ 指定值,且不会补零或丢弃 —— 这符合多数真实场景(如批量发送、分页处理),但如果你硬性要求“所有块大小严格相等”,它不满足条件,得自己丢弃尾部或填充。
使用前确认编译器支持(GCC 13+ / Clang 15+ / MSVC 19.33+),并包含 <ranges> 和 <vector>:
立即学习“C++免费学习笔记(深入)”;
#include <ranges>
#include <vector>
// ...
auto chunks = arr | std::views::chunk(3);
for (const auto& chunk : chunks) {
// chunk 是 std::ranges::subrange,不是 vector;需 .begin()/.end() 遍历
}
- 不支持随机访问
chunk[0],必须用迭代器遍历 - 每个
chunk不是独立容器,生命周期依赖原arr - 无法直接获取块内元素个数,得用
std::ranges::distance(chunk)
需要返回 std::vector<std::vector<T>> 时,怎么写最安全?
这是最常被搜索的场景:函数输入数组和块大小,输出二维向量。关键点是预分配外层容量,避免多次内存重分配;同时对空输入和零块大小做防御。
示例函数逻辑:
template<typename T>
std::vector<std::vector<T>> chunk_vector(const std::vector<T>& v, size_t chunk_size) {
if (chunk_size == 0 || v.empty()) return {};
std::vector<std::vector<T>> result;
result.reserve((v.size() + chunk_size - 1) / chunk_size); // 向上取整
for (size_t i = 0; i < v.size(); i += chunk_size) {
result.emplace_back(v.begin() + i,
v.begin() + std::min(i + chunk_size, v.size()));
}
return result;
}
-
result.reserve()算的是向上取整:(n + k - 1) / k,不是n / k - 用
emplace_back直接构造,避免临时对象拷贝 - 传入
const std::vector<T>&防止误修改原数据
用原始数组(T* + size_t)切分时,指针运算要注意什么?
比 std::vector 更底层,也更容易出错。核心风险是:指针算术中混用有符号/无符号类型,或忽略对齐与生命周期。
例如,给定 int* arr 和 size_t len,块起始地址是 arr + i,但结束地址必须是 arr + std::min(i + chunk_size, len) —— 如果 i + chunk_size 溢出 size_t(极罕见),或 i 超过 len,就会越界。
建议始终用 size_t 做索引,并加一层保护:
if (i >= len) break; size_t end = std::min(i + chunk_size, len); // 使用 [arr + i, arr + end) 区间
另外,如果原始数组是栈分配(如 int a[10]),确保切分后不长期持有指针,否则函数返回后指针悬空。
块大小为 0、数组为空、chunk_size > len 这三种边界情况,都得单独判断,不然 std::min 没问题,但后续逻辑可能崩。


















