std::transform要求目标容器预先分配足够空间,否则越界;支持单/双输入映射,不检查边界;与views::transform不同,它立即执行而非延迟求值。

std::transform 用法:目标容器必须预先分配空间
直接调用 std::transform 不会自动扩容目标容器,如果 dest 是空的 std::vector,写入会越界——这是最常踩的坑。
正确做法是提前用 resize() 或构造时指定大小:
std::vector<int> src = {1, 2, 3, 4};
std::vector<int> dest(src.size()); // 必须先分配
std::transform(src.begin(), src.end(), dest.begin(), [](int x) { return x * 2; });也可以用 std::back_inserter 配合空容器,但要注意性能开销(每次插入触发可能的内存重分配):
std::vector<int> dest;
dest.reserve(src.size()); // 建议加这句避免反复 realloc
std::transform(src.begin(), src.end(), std::back_inserter(dest), [](int x) { return x * 2; });输入迭代器范围必须合法,且目标起始位置要足够容纳结果
std::transform 不检查边界。若 dest 的起始迭代器之后可用空间不足,行为未定义——编译器不会报错,运行时可能崩溃或静默写坏内存。
立即学习“C++免费学习笔记(深入)”;
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 确保
std::distance(dest_begin, dest_end) >= std::distance(src_begin, src_end) - 对
std::array或 C 数组,务必确认目标数组长度 ≥ 源长度 - 对
std::vector,用dest.size() >= src.size()做前置断言更安全
双容器映射:用两个输入范围 + 一个输出范围
除了单输入映射,std::transform 还支持二元操作,比如向量逐元素相加:
std::vector<int> a = {1, 2, 3};
std::vector<int> b = {10, 20, 30};
std::vector<int> result(a.size());
std::transform(a.begin(), a.end(), b.begin(), result.begin(), std::plus<>{}); // result = {11, 22, 33}注意点:
- 第二个输入范围(
b.begin())长度必须 ≥ 第一个范围,否则读越界 -
std::plus<>是 C++14 起的透明函数对象,比std::plus<int>更泛化 - 若只需部分元素参与(如前 N 个),显式传入
a.begin() + N和b.begin() + N
和 range-v3 / C++20 views::transform 的关键区别
std::transform 是就地计算并写入,不产生新容器;而 views::transform 返回延迟求值的 view,不分配内存也不执行变换,直到你遍历或转成容器:
// C++20
auto doubled_view = src | std::views::transform([](int x) { return x * 2; });
std::vector<int> dest(doubled_view.begin(), doubled_view.end()); // 此刻才真正计算所以如果你要的是“懒映射”或链式操作(比如 filter + transform),别硬套 std::transform;但若只是简单、一次性、确定大小的转换,std::transform 更轻量、更可控。
容易被忽略的是:std::transform 对输入容器无修改要求,但若 lambda 捕获了非 const 引用并试图修改源元素,就可能引发意外副作用——尤其是当源和目标是同一容器时(比如原地平方),必须确保迭代器不重叠或使用 std::transform 的单输入重载配合 std::make_move_iterator 等手段谨慎处理。

















