std::partition仅保证满足谓词的元素在前、不满足的在后,内部顺序未定义;需保持相对顺序应使用std::stable_partition;谓词须为纯函数,迭代器需可写且非const,返回分界迭代器。

std::partition 会改变原容器顺序,且不保证分区内部有序
它只保证满足谓词的元素全在前半段、不满足的全在后半段,但各自内部顺序是未定义的(不是稳定排序)。如果你需要保持相对顺序,得用 std::stable_partition —— 它开销更大,但保留了原序列中相同类别元素的先后关系。
常见错误是误以为 std::partition 像 std::sort 那样“整理”数据,结果发现偶数/奇数分组后,偶数之间顺序乱了,还以为是迭代器写错了。
- 适用场景:快速二分类(如把空指针移到末尾、把无效ID过滤到后面)
- 不适用场景:需要按原始顺序输出满足条件的子序列
- 性能上,
std::partition是 O(n),单次遍历;std::stable_partition通常是 O(n log n) 或额外 O(n) 空间
传入的谓词必须是纯函数,不能有副作用
std::partition 内部可能对同一元素多次调用谓词(尤其在某些标准库实现中做优化判断时),如果谓词里修改了外部状态(比如递增计数器、打印日志、改变全局变量),行为不可预测。
示例中容易踩的坑:
立即学习“C++免费学习笔记(深入)”;
int count = 0;
auto pred = [&count](int x) { return ++count, x > 0; }; // ❌ 危险!count 增加次数不确定
std::vector<int> v = {1, -2, 3};
std::partition(v.begin(), v.end(), pred); // count 最终可能是 2、3 或 4
- 谓词应只读取参数和捕获的 const 变量
- 若需调试,用
std::copy_if+ 手动构造新容器更安全 - lambda 捕获列表推荐用
[=]或[&] + const显式约束
迭代器范围必须合法,且不能是 const_iterator
std::partition 要求输入的是可写迭代器(RandomAccessIterator,且 value_type 可移动/交换),所以不能传 v.cbegin()、std::as_const(v).begin(),也不能对 const std::vector<T> 调用。
错误现象通常是编译失败,报错信息类似:
error: no matching function for call to 'partition(... const_iterator ...)'
- 确保用
v.begin()/v.end(),而非v.cbegin() - 容器本身不能是 const 限定的
- 对
std::array、std::deque同样适用,但std::list推荐用其成员函数list::partition(更高效)
返回值是指向第二分区起始位置的迭代器
这个返回值非常关键,但常被忽略。它不是布尔值,也不是 void —— 它指向第一个「不满足谓词」的元素,也就是前后两段的分界点。
你可以直接用它切分数据,比如提取所有满足条件的元素:
std::vector<int> v = {1, -2, 3, -4, 5};
auto it = std::partition(v.begin(), v.end(), [](int x) { return x > 0; });
// it 指向 -2 或 -4(取决于实现),但一定在所有正数之后、负数之前
std::vector<int> positives(v.begin(), it); // ✅ 安全截取
- 别假设
it == v.end()表示“全满足”,要实际检查 - 如果后续还要对前半段操作,直接用
v.begin()到it这段,别重新partition - 跨线程使用该迭代器前,确保原容器没被其他线程修改
it,只要满足语义就合法。别硬编码偏移量。











