std::partition原地重排,不保证组内顺序,返回指向首不满足元素的迭代器;与stable_partition相比开销小但不保序,使用时需注意谓词逻辑、捕获方式、副作用及迭代器有效性。
partition 会原地重排,不保证原始顺序
std::partition 把满足谓词的元素“全挪到前面”,不满足的“全挪到后面”,但同一组内的相对顺序不保留。这和 std::stable_partition 有本质区别——后者开销大但保序。
常见错误是误以为它像 filter 那样生成两个新容器;其实它只返回一个迭代器,指向第一个“不满足条件”的位置:
std::vector v = {1, 4, 2, 5, 3};
auto pivot = std::partition(v.begin(), v.end(), [](int x) { return x % 2 == 0; });
// v 可能变成 {4, 2, 5, 1, 3} 或 {2, 4, 5, 1, 3} 等,只要偶数全在前、奇数全在后即可
// pivot 指向 v[2](即第一个奇数)
- 用前先确认是否允许打乱组内顺序
- 若需保序(比如日志按状态分组且要保持时间先后),必须换用
std::stable_partition - 返回的迭代器可用于快速切分:
std::vector evens(v.begin(), pivot)、std::vector odds(pivot, v.end())
谓词写错会导致 partition 行为完全反直觉
传给 std::partition 的谓词决定“哪边是真值区间”。写反逻辑(比如把 x > 10 写成 x )不会报错,但结果和预期相反,而且很难一眼发现。
更隐蔽的是捕获变量时作用域失效或值变化:
立即学习“C++免费学习笔记(深入)”;
int threshold = 5;
std::partition(v.begin(), v.end(), [threshold](int x) { return x > threshold; }); // ✅ 安全
std::partition(v.begin(), v.end(), [&threshold](int x) { return x > threshold; }); // ⚠️ 若 threshold 在 partition 过程中被改,行为未定义
- 优先用值捕获(
[=]或明确变量名)而非引用捕获([&]) - 谓词里避免副作用(如修改外部变量、打印、抛异常)——标准不保证调用次数和顺序
- 调试时可先用
std::count_if验证谓词逻辑:std::count_if(v.begin(), v.end(), pred)看有多少元素应归入前段
partition 和 remove_if 的关键区别在哪
两者都重排容器,但目标不同:std::partition 是“分类”,std::remove_if 是“剔除”。前者不改变容器大小,后者需配合 erase 才真正删除。
例如想分离正负数并保留零: