STL算法中的for_each和transform是处理容器元素时非常实用的工具,前者主要用于遍历容器执行自定义操作,后者则可以在遍历的同时完成元素的转换并输出到新的容器。两者都位于algorithm头文件中,是泛型编程的典型应用。

for_each算法的基本用法
for_each的作用是遍历容器中的每个元素,对每个元素执行指定的可调用对象,该可调用对象可以是函数、函数对象或者lambda表达式。它的返回值就是传入的可调用对象,因此如果需要获取遍历过程中的状态,可以通过可调用对象来保存。
下面是使用for_each遍历vector并打印元素的示例:
#include <algorithm>
#include <vector>
#include <iostream>
int main() {
std::vector<int> nums = {1, 2, 3, 4, 5};
// 使用lambda表达式作为可调用对象,打印每个元素
std::for_each(nums.begin(), nums.end(), [](int num) {
std::cout << num << " ";
});
std::cout << std::endl;
return 0;
}
如果需要统计遍历过程中的信息,也可以自定义函数对象来保存状态:
#include <algorithm>
#include <vector>
#include <iostream>
// 自定义函数对象,统计元素总和
struct SumCalculator {
int sum = 0;
void operator()(int num) {
sum += num;
}
};
int main() {
std::vector<int> nums = {1, 2, 3, 4, 5};
SumCalculator calc = std::for_each(nums.begin(), nums.end(), SumCalculator());
std::cout << "元素总和为:" << calc.sum << std::endl;
return 0;
}
transform算法的基本用法
transform算法的作用是对输入区间的每个元素应用转换操作,将结果输出到指定的目标区间,它有两种常用重载形式:一种是单输入区间的转换,另一种是双输入区间的逐元素操作转换。需要注意的是,目标容器需要提前预留足够的空间,否则会导致未定义行为。
单输入区间的transform示例
下面的示例将vector中的每个元素乘以2,结果保存到新的vector中:
#include <algorithm>
#include <vector>
#include <iostream>
int main() {
std::vector<int> source = {1, 2, 3, 4, 5};
std::vector<int> target;
// 提前预留空间,避免扩容问题
target.reserve(source.size());
// 使用back_inserter插入结果,也可以提前resize target后使用target.begin()
std::transform(source.begin(), source.end(), std::back_inserter(target), [](int num) {
return num * 2;
});
for (int num : target) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
双输入区间的transform示例
transform还支持两个输入区间的逐元素操作,比如将两个vector的对应元素相加:
#include <algorithm>
#include <vector>
#include <iostream>
int main() {
std::vector<int> a = {1, 2, 3};
std::vector<int> b = {4, 5, 6};
std::vector<int> result;
result.reserve(a.size());
// 两个输入区间的对应元素相加
std::transform(a.begin(), a.end(), b.begin(), std::back_inserter(result), [](int x, int y) {
return x + y;
});
for (int num : result) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
for_each和transform的差异对比
两者虽然都可以遍历容器,但核心定位不同,具体差异如下:
| 对比维度 | for_each | transform |
|---|---|---|
| 核心功能 | 遍历元素执行操作,不要求返回新值 | 遍历元素执行转换,输出转换后的结果 |
| 返回值 | 传入的可调用对象 | 目标区间的尾后迭代器 |
| 目标容器要求 | 无要求,不需要额外空间 | 需要目标区间有足够空间,或配合插入迭代器使用 |
| 适用场景 | 遍历打印、修改原元素、统计等无输出转换的场景 | 元素转换、两个容器逐元素运算等有输出结果的场景 |
使用注意事项
- 使用for_each修改原容器元素时,可调用对象的参数需要是引用类型,否则无法修改原元素:
[](int& num) { num *= 2; } - 使用transform时,目标区间的大小必须不小于输入区间的大小,否则会导致越界访问
- 两个算法的输入区间迭代器需要是输入迭代器及以上类型,支持前向遍历即可
- 如果转换操作比较复杂,建议将可调用对象单独定义,避免lambda表达式过于冗长
STL算法的设计遵循泛型编程思想,for_each和transform不仅适用于vector,也适用于所有支持对应迭代器类型的容器,比如list、deque、数组等,使用时只需要传入对应的begin和end迭代器即可。