将std::vector拆分为指定大小子vector的可读实现及std::bad_alloc问题
嘿,我来帮你搞定这个问题!首先你遇到的std::bad_alloc异常,九成是因为你用std::copy的时候,目标子vector没有预先分配足够的内存空间就直接往里写了——std::copy可不会自动帮目标容器扩容,如果传入的vec.begin()指向的是空vector,或者size小于要复制的元素数量,就会触发内存访问越界,最终抛出bad_alloc。
接下来我给你几种高可读性的实现方式,既解决异常问题,又让代码清晰易懂:
方法一:用范围构造函数(最简洁直观)
直接利用vector的范围构造能力,每次从原vector中截取一段迭代器范围来创建子vector,完全不用手动处理内存和copy,代码可读性拉满:
#include <vector> #include <iostream> #include <iterator> // 用于std::next std::vector<std::vector<int>> splitIntoChunks(const std::vector<int>& input, size_t chunkSize) { std::vector<std::vector<int>> chunks; for (size_t i = 0; i < input.size(); i += chunkSize) { // 计算当前chunk的结束位置,避免超出原vector末尾 auto endIter = std::next(input.begin(), std::min(i + chunkSize, input.size())); // 直接用迭代器范围构造子vector,自动处理内存分配 chunks.emplace_back(input.begin() + i, endIter); } return chunks; } // 测试你的示例输入 int main() { std::vector<int> cam = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17}; auto result = splitIntoChunks(cam, 5); // 打印验证结果 for (const auto& chunk : result) { std::cout << "["; for (size_t j = 0; j < chunk.size(); ++j) { if (j != 0) std::cout << ", "; std::cout << chunk[j]; } std::cout << "]\n"; } return 0; }
运行这段代码会直接输出你想要的结果:
[1, 2, 3, 4, 5]
[6, 7, 8, 9, 10]
[11, 12, 13, 14, 15]
[16, 17]
方法二:修复你原来的std::copy写法
如果你坚持想用std::copy,那必须确保目标子vector有足够的空间,这里给你两种修复方式:
方式A:预先给子vector分配内存
先计算当前chunk的大小,用resize预分配空间,再执行copy:
std::vector<std::vector<int>> splitIntoChunks(const std::vector<int>& input, size_t chunkSize) { std::vector<std::vector<int>> chunks; for (size_t i = 0; i < input.size(); i += chunkSize) { size_t currentChunkSize = std::min(chunkSize, input.size() - i); std::vector<int> subVec; subVec.resize(currentChunkSize); // 预先分配足够空间 std::copy(input.begin() + i, input.begin() + i + currentChunkSize, subVec.begin()); chunks.push_back(subVec); } return chunks; }
方式B:用std::back_inserter自动扩容
back_inserter会自动调用子vector的push_back,不需要手动分配空间,更安全:
#include <iterator> // 必须包含这个头文件 std::vector<std::vector<int>> splitIntoChunks(const std::vector<int>& input, size_t chunkSize) { std::vector<std::vector<int>> chunks; for (size_t i = 0; i < input.size(); i += chunkSize) { auto endIter = std::next(input.begin(), std::min(i + chunkSize, input.size())); std::vector<int> subVec; std::copy(input.begin() + i, endIter, std::back_inserter(subVec)); chunks.push_back(subVec); } return chunks; }
为什么你的原代码会抛出bad_alloc?
假设你原来的代码是类似这样的:
// 错误示例! std::vector<int> vec; std::copy(cam.begin() + start, cam.begin() + end + 1, vec.begin());
这里vec是空的,vec.begin()指向的是未初始化的内存地址,std::copy试图往这个位置写入元素,会直接触发内存访问越界,进而导致bad_alloc异常(或者直接崩溃,取决于编译器和系统)。
总结一下,最推荐的是方法一的范围构造函数写法,代码简洁、可读性高,还能避免手动内存管理的错误。
内容的提问来源于stack exchange,提问作者T. Swiz

