Item 21: Always have comparison functions return false for equal values.
严格弱序( strict weak ordering )
先补充下严格弱序的概念: 对两个变量 x 和 y:
x > y等同于y < xx == y等同于!(x < y) && !(x > y)
要想严格弱序,就需要遵循如下规则:
- 每个变量值必须等于其本身(
irreflexivity):x < x永远不能为true - 不对称性(
asymmetry):如果x < y,那么y < x就不能为true - 有序性必须可传递性:如果
x < y并且y < z,那么x < z - 值相同必须具有可传递性:如果
x == y并且y == z,那么x == z
为什么?
1. 关联容器中的比较算法
比如我们创建一个 set , 用 less_euqal 作为比较类型,然后插入两个 10 :
1 | set<int, less_equal<int>> s; |
我们将第一个 10 记为 10A, 第二个 10 记为 10B, 我们在插入 10B 的时候会检查是否与 10A 相同, 我们用的是 less_equal,下面的表达式会为假,就会重复插入,显然不合理。:
1 | !(10A <= 10B) && !(10B <= 10A) // !(true) && !(true) |
另外在 multiset 中也不行:
1 | multiset<int, less_equal<int>> s; |
当我们想要一个 equal_range, 10A 和 10B 同样认为是不等,永远不会在同一个区间。
2. sort 算法
对于 std::sort,当容器里面元素个数大于 _S_threshold 的值时(16),就会使用快速排序,会将所有的元素与中间值比较是无边界保护的,实现如下:
1 | template<typename _RandomAccessIterator, typename _Tp, typename _Compare> |
如果传入的 vector 中,后面的元素完全相等, __comp()函数一直返回 true ,在进行快速排序的时候,++first 就可能越界失效,导致 coredump。