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











