直接传函数对象给std::sort即可,推荐用auto推导lambda类型,避免函数指针签名错误和lambda捕获导致的悬垂引用。

std::sort 里传自定义比较函数最直接
绝大多数时候你不是真要“自定义 STL 容器”,而是想对 std::vector、std::array 这类序列容器排序,这时直接给 std::sort 传函数对象就行,不用动容器本身。
常见错误是写成函数指针却忽略调用约定,或用 lambda 捕获了局部变量导致悬垂引用:
- 用
auto推导 lambda 类型最安全,比如auto cmp = [](int a, int b) { return a > b; };,再传给std::sort(v.begin(), v.end(), cmp) - 如果必须用函数指针,确保签名是
bool(int, int),不能带const &(除非参数类型本身就是引用) - 避免在 lambda 里捕获栈变量地址,比如
[&x]() { return a —— <code>x出作用域后行为未定义
构造 std::set / std::map 时指定比较类型
真正需要“自定义容器比较逻辑”的场景,通常是 std::set 或 std::map 这类关联容器。它们的模板参数第二项就是比较器类型,不是函数值。
关键点在于:你传的是类型,不是实例;容器内部会默认构造一个该类型的对象来调用 operator():
立即学习“C++免费学习笔记(深入)”;
- 写仿函数类时,
operator()必须是const成员函数,且接受两个const引用参数,比如struct Cmp { bool operator()(const std::string& a, const std::string& b) const { return a.size() - 用 lambda 的话,得用
decltype提取类型:auto cmp = [](const int& a, const int& b) { return a % 10 s(cmp);—— 注意后面还得传一个实参初始化它 - 别用
std::function当模板参数,它有运行时开销,且不满足Compare要求(必须是可默认构造、可复制)
std::priority_queue 自定义比较要注意方向
std::priority_queue 的第三个模板参数是“大顶堆判断逻辑”,但它的含义和 std::sort 相反:返回 true 表示第一个参数“优先级更低”,也就是会被沉到堆底。
所以如果你想要小顶堆,比较函数得写成 a > b,而不是直觉的 a :
- 正确的小顶堆:
std::priority_queue<int std::vector>, std::greater<int>> q;</int></int>或自定义[](int a, int b) { return a > b; } - 常见错误是抄了
std::sort的写法:[](int a, int b) { return a ,结果得到的是大顶堆 - 如果元素是自定义类型,务必确保比较逻辑严格弱序(无相等环、传递性),否则
push可能崩溃或行为异常
std::unordered_map / unordered_set 用的是哈希 + 等价判断
哈希容器不叫“比较函数”,而叫“等价谓词(KeyEqual)”,它配合哈希函数一起工作:先算哈希分桶,再用 KeyEqual 在桶内逐个比对是否真正相等。
这意味着你不能只改比较逻辑,还必须同步调整哈希函数,否则会出现“能插入重复 key”或“查不到已存 key”:
-
KeyEqual默认是std::equal_to<key></key>,签名是bool(const Key&, const Key&),不带const &修饰的引用会编译失败 - 如果自定义了哈希(比如按字符串长度哈希),那
KeyEqual就不能只比长度,否则两个不同字符串只要长度相同就被认为相等 —— 必须保证:哈希相等 ⇒KeyEqual为 true,但反过来不强制 - 实践中更稳妥的做法是重载
operator==和std::hash特化,而不是单独传KeyEqual
真正麻烦的是跨容器复用比较逻辑:仿函数类得头文件可见,lambda 无法作为模板参数传递(除非用 decltype 加实参),而 std::function 又破坏了零开销原则。多数情况,就老老实实用仿函数类或顶层函数,别为了“简洁”牺牲清晰性和可维护性。


















