参考:http://biasee.com/2016/01/22/STL-sort-segmentation-fault/
C++ std的sort,compare函数写成下面这样,可能出现segmentation fault,因为写成a>=b是错误的,不符合stl的strict weak ordering关系。
bool cmp(int a,int b){
return a>=b;
}
使用C++的标准模板库(Standard Template Library,STL)中的std::sort函数进行排序时,如果你的比较函数(这里是cmp)的实现是return a>=b;,可能会导致程序出现分段错误(Segmentation Fault)。
原因在于,这个比较函数并没有遵守STL所要求的严格弱序(Strict Weak Ordering)规则。这个规则可以用以下四个准则来描述:
-
对于所有的x,cmp(x, x)必须返回false。也就是说,不应该存在任何一个元素,让比较函数判断它“小于或等于”自身。
-
如果cmp(x, y)为true,那么cmp(y, x)必须为false。也就是说,如果x“小于”y,那么y不应该“小于或等于”x。
-
如果cmp(x, y)和cmp(y, z)都为true,那么cmp(x, z)也必须为true。这个属性叫做传递性。
-
对于所有的x和y,cmp(x, y)和cmp(y, x)至少有一个必须为false。这个属性叫做非对称性。
在函数
bool cmp(int a,int b){ return a>=b; }
中,违反了第一条和第二条规则,即自反性和反对称性。例如,当a和b相等时,cmp(a, b)和cmp(b, a)都会返回true,这违反了STL所要求的严格弱序关系。
正确的实现应该是return a < b;或return a > b;,取决于需要的是升序还是降序排序。这样的实现满足了STL的严格弱序要求。
也就是说,对于C++里面自定义的比较函数,如果想让它作为std::sort或其他STL算法的参数,那么函数应该遵守严格弱序(Strict Weak Ordering)规则。在这种情况下,不能返回a >= b,因为这样的定义违反了严格弱序的自反性和反对称性。
(但是,如果你的比较函数并不用于STL算法,那么严格弱序的规则就不是必须的。)
严格弱序典型实现
严格弱序规则的一个典型实现是return a < b(用于升序排序)或return a > b(用于降序排序)。如果比较函数cmp是用于std::sort或其他STL算法的,那么它应该返回a < b或a > b,而不是a >= b或a <= b。
例如:
std::sort:这是一个用于对容器进行排序的算法,可以接受一个比较函数来定义排序规则。
std::vector<int> v = {3, 2, 5, 1, 4};
auto cmp = [](int a, int b) { return a > b; }; // 按降序排序
std::sort(v.begin(), v.end(), cmp);
当自定义的比较函数(例如cmp)被用作std::sort或其他STL算法的参数时,需要遵循严格弱序(Strict Weak Ordering)规则。在这个例子中,cmp就是作为参数传递给std::sort的自定义比较函数,它满足严格弱序规则,std::sor才能正确地工作。
cmp的解释
auto cmp = [](int a, int b) { return a > b; };
这是定义了一个C++的lambda函数(也叫做匿名函数)并将它赋值给了一个名为cmp的变量。
[](int a, int b) { return a > b; }这部分就是一个lambda函数。具体来说:
[]:这是lambda函数的捕获列表,用于指定哪些在创建该lambda的作用域内的外部变量可以在lambda函数内部使用。在这个例子中,捕获列表为空,意味着这个lambda函数不使用任何外部变量。
(int a, int b):这是lambda函数的参数列表,类似于普通函数的参数列表。在这个例子中,这个lambda函数接受两个int类型的参数,分别命名为a和b。
{ return a > b; }:这是lambda函数的主体,也就是函数的实际执行代码。在这个例子中,这个lambda函数比较a和b的大小,并返回a > b的结果(也就是如果a大于b则返回true,否则返回false)。
std::sort(v.begin(), v.end(), cmp);
这是对v(一个std::vector容器)里的元素进行排序,排序规则由cmp这个函数对象(在这里就是lambda函数)来确定。在这个例子中,cmp是一个lambda函数,定义为[](int a, int b) { return a > b; },所以std::sort会按照降序(从大到小)来排序v中的元素。
作为STL算法中的参数传入的时候,比较函数的返回类型必须是bool,并且它们必须满足严格弱序规则。
一些示例
- 对一个std::vector中的元素进行降序排序:
std::vector<int> v = {3, 2, 5, 1, 4};
auto cmp = [](int a, int b) { return a > b; };
std::sort(v.begin(), v.end(), cmp);
- 找出一个std::vector中最长的字符串:
std::vector<std::string> v = {"cat", "antelope", "dog", "elephant"};
auto cmp = [](const std::string& a, const std::string& b) { return a.size() < b.size(); };
auto longest = *std::max_element(v.begin(), v.end(), cmp);
- 在一个已经按照长度排序的std::vector中查找一个指定长度的字符串:
std::vector<std::string> v = {"I", "am", "a", "list", "of", "words"};
auto cmp = [](const std::string& a, const std::string& b) { return a.size() < b.size(); };
std::sort(v.begin(), v.end(), cmp);
std::string to_find = "four";
bool found = std::binary_search(v.begin(), v.end(), to_find, cmp);
这些都是STL中可以接受比较函数作为参数的算法的例子。注意在这些例子中,比较函数的返回类型必须是bool,并且它们必须满足严格弱序规则,否则可能导致未定义的行为。