一、Strict Weak Ordering(严格弱顺序)
Strict Weak Ordering是C++ STL中各种算法都用到的一个概念。
- Strict:s < s 要必须返回false;
- Weak:s < t 和 t < s都返回false时,就说明s == t;
- Ordering:s < t为true 并且 t < z为true,则s < z也必须为true。
二、std::sort导致core
对于std::sort(),当容器里面元素的个数大于_S_threshold
(stl的这个默认值是16)的枚举常量值时,会使用快速排序。
/// This is a helper function for the sort routine.
template<typename _RandomAccessIterator, typename _Size, typename _Compare>
void
__introsort_loop(_RandomAccessIterator __first,
_RandomAccessIterator __last,
_Size __depth_limit, _Compare __comp)
{
while (__last - __first > int(_S_threshold))
{
if (__depth_limit == 0)
{
_GLIBCXX_STD_A::partial_sort(__first, __last, __last, __comp);
return;
}
--__depth_limit;
_RandomAccessIterator __cut =
std::__unguarded_partition_pivot(__first, __last, __comp);
std::__introsort_loop(__cut, __last, __depth_limit, __comp);
__last = __cut;
}
}
/// This is a helper function...
template<typename _RandomAccessIterator, typename _Tp, typename _Compare>
_RandomAccessIterator
__unguarded_partition(_RandomAccessIterator __first,
_RandomAccessIterator __last,
const _Tp& __pivot, _Compare __comp)
{
while (true)
{
while (__comp(*__first, __pivot))
++__first;
--__last;
while (__comp(__pivot, *__last))
--__last;
if (!(__first < __last))
return __first;
std::iter_swap(__first, __last);
++__first;
}
}
注意这里:
while (__comp(*__first, __pivot))
++__first;
这两行代码里面,__pivot
是中间值,__first
是迭代器,假设我们的__comp
函数对于相等的值返回true
,那么如果一个容器里面最后一段元素所有值都相等,那么__comp(*__first,__pivot)
就恒为真。迭代器往前移的时候,终会移过最后一个元素,于是迭代器失效,程序core。
我们正是在生产环境遇到了这个问题导致了core。
其实下面的两行代码也可能导致core,原理是一样的,只是当时没有遇到,后面在代码测试过程中介绍。
while (__comp(__pivot, *__last))
--__last;
如果一个comp函数要满足Strict Weak Ordering,意味着它应该满足如下特征:
- 反自反性:也即comp(x, x)必须是false
- 非对称性:也即如果comp(x, y)和comp(y, x)的结果必然相反
- 可传递性:也即如果comp(x, y)为true,comp(y, z)为true,那么comp(x, z)必然为true
下面这个cmp函数明显违背了1、2两条。
bool cmp(int a,int b)
{
return a<=b;
}
在Effective STL一书中有这么一条:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uPkl26jQ-1648120967889)(/upload/2021/10/image-f72af105562c4dd49977327125f67df5.png)]
三、一个测试例子
#include <vector>
#include <algorithm>
using namespace std;
struct A
{
A(int _a) : n (_a){}
int n;
};
bool comp(A* a, A* b)
{
return a->n <= b->n;
}
int main(int argc, char **argv)
{
vector<A*> S;
for (int i = 0; i < 100; ++i)
{
S.push_back(new A(i));
S.push_back(new A(i));
}
std::sort(S.begin(), S.end(), comp);
return 0;
}
上面这个因为while (__comp(__pivot, *__last))
一直是true,__last
迭代器越界失效,导致程序core。
#include <vector>
#include <algorithm>
using namespace std;
struct A
{
A(int _a) : n (_a){}
int n;
};
bool comp(A* a, A* b)
{
return a->n <= b->n;
}
int main(int argc, char **argv)
{
vector<A*> S;
for (int i = 0; i < 100; ++i)
{
S.push_back(new A(i));
S.push_back(new A(i));
S.push_back(new A(i));
S.push_back(new A(i));
S.push_back(new A(i));
S.push_back(new A(i));
S.push_back(new A(i));
S.push_back(new A(i));
S.push_back(new A(i));
}
std::sort(S.begin(), S.end(), comp);
return 0;
}
上面这个因为while (__comp(__pivot, *__first))
一直是true,__first
迭代器越界失效,导致程序core。