std::transform是最轻量可控的批量转换工具,但不管理目标空间且不检查越界;需确保目标容器已分配足够空间或使用back_inserter等插入迭代器,否则将导致写入越界或结果为空。

直接说结论:std::transform 是最轻量、最可控的批量转换工具,但它不自动分配目标空间,也不检查越界——用错就崩,写对就稳。
为什么std::transform经常报“写入越界”或“结果为空”?
根本原因:它从不管理目标容器大小,只按迭代器范围机械地写入。你给它一个 std::vector,它就往那个地址写,不管后面有没有空间。
- 常见错误:对空
vector调用std::transform,且没提前resize()或用back_inserter - 正确做法:目标容器必须已分配足够空间,或使用插入型迭代器
- 别指望它像 python 的
map()那样返回新容器——它只做“搬运工”,不做“包工头”
std::transform单序列转换(一元操作)怎么写才安全?
适用于:每个元素独立计算,比如转大写、取绝对值、开方等。必须确保目标区间长度 ≥ 源区间长度。
std::vector src = {1, -4, 9, -16}; std::vector dst(src.size()); // 关键:提前分配空间 std::transform(src.begin(), src.end(), dst.begin(), [](int x) { return x * x; }); // 平方 // dst 现在是 {1, 16, 81, 256}
- 源区间:
src.begin()到src.end() - 目标起始:
dst.begin(),必须可写且容量足够 - 函数对象:接受一个参数,返回转换后值
- 如果目标容器是
std::list或std::deque,同样要先resize()或用std::inserter
std::transform双序列转换(二元操作)要注意什么?
适用于:两两对齐运算,如向量加法、字符串逐字符比较、合并两个数组。两个输入区间长度必须一致,否则行为未定义。
立即学习“C++免费学习笔记(深入)”;
std::vector a = {1, 2, 3}; std::vector b = {10, 20, 30}; std::vector result(a.size()); std::transform(a.begin(), a.end(), b.begin(), result.begin(), std::plus{}); // 或 [](int x, int y) { return x + y; }); // result == {11, 22, 33}
- 第二个源区间只传起始迭代器
b.begin(),长度由第一个区间决定 - 如果
b实际比a短,读b.end()之后内存会触发未定义行为(不是抛异常,是可能静默崩溃) -
std::plus是函数对象,不是函数指针;c++17 起支持,比 Lambda 更轻量{}
想边转换边扩容?别硬刚,用std::back_inserter
当目标容器初始为空,又不想手动 resize(),就靠它把每次转换结果自动 push_back 进去。
std::vector src = {1, 2, 3}; std::vector dst; std::transform(src.begin(), src.end(), std::back_inserter(dst), [](int x) { return std::to_string(x * 10); }); // dst == {"10", "20", "30"}
-
std::back_inserter(dst)返回一个输出迭代器,内部调用dst.push_back() - 性能略低于预分配空间(多次
realloc),但语义清晰、不易出错 - 仅适用于支持
push_back的容器(vector、deque、list),不能用于Array或原生数组
最容易被忽略的一点:所有迭代器必须指向有效、可访问的内存。哪怕你用 back_inserter,如果 src 区间本身是悬垂迭代器(比如 vector 已被 move 走),transform 一样立刻 UB。它不验证,只执行。