@(c++)
core 的原因
c++ 標準庫 sort() 默認采用 < 這個 operator 來排序的, 另個一個重載函數(shù)增加第三個參數(shù)煮落,指定一個比較的函數(shù),函數(shù)接受兩個參數(shù)篱蝇。
對于基礎類型(int梆砸,float..)凭戴,直接調用 sort(start,end) 即可,對于非基礎類型的結構體酪碘,可以通過重載對象的 < 運算符或者提供一個比較函數(shù)朋譬。
詳見
本文從一個 core 說起 相信很多人在編寫使用 sort 都在這個地方翻車,
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
class CompareGreater {
public:
bool operator()(const int* left, const int* right)
{
return *left >= *right;
}
};
int main(int argc, char *argv[])
{
vector<int *> verPInt;
for (int i = 0; i < 18; i++) { // will coredump
int *pInt = new int;
if (pInt == NULL) {
cout << "new faile" << endl;
goto final;
}
*pInt = 1;
verPInt.push_back(pInt);
}
sort(verPInt.begin(), verPInt.end(), CompareGreater());
for (vector<int *>::iterator iter = verPInt.begin(); iter != verPInt.end(); ++iter) {
cout << **iter;
}
cout << endl;
final:
for (vector<int *>::iterator iter = verPInt.begin(); iter != verPInt.end(); ++iter) {
delete *iter;
*iter = NULL;
}
return 0;
}
gdb 查看堆棧兴垦,發(fā)現(xiàn)是 core 在比較函數(shù)里面徙赢。
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x000055e88121e00c in CompareGreater::operator()(int const*, int const*) ()
上述代碼字柠,所有元素值相同,當個數(shù)大于等于 16個 的時候就會 coredump狡赐,查看說明窑业,core 的原因是 :
<font color=#0099ff size=5>std::sort()在排序時,比較函數(shù)對相等的元素應該返回 false枕屉!如果返回 true常柄,會導致程序coredump</font>
因為定義 cmp(x,x) 返回 true 不符合 Strict_weak_orderings,標準庫算法里面很多都要求滿足 Strict_weak_orderings搀擂,使用時需要格外注意西潘,避免翻車。
上述例子代碼只需修改比較函數(shù)中哨颂,將 >=
改為 >
即可修復喷市。
為什么是元素個數(shù)大于等于 16個 呢,從 STL 源碼可以發(fā)現(xiàn)威恼,由于 std::sort() 的排序分2種品姓,當元素個數(shù) >16 <font color=#0099ff>(_S_threshold = 16)</font> 時選擇快速排序,<=16 個則選擇插入排序 (對象少時快排性能不理想)箫措。按照快排原理腹备,每次都是遍歷所有值和一個中間值比較,小的放左邊蒂破,大的放右邊馏谨。從STL源代碼可看出别渔,std::sort() 在遍歷比較時附迷,是沒有加邊界保護的。如果比較相等的元素返回真哎媚,則在極端情況下 (如所有元素值相等時) __first 會出現(xiàn)訪問越界喇伯,導致coredump。
STL 源碼 : /usr/include/c++/7/bits/stl_algo.h
(具體目錄)
深層次的坑
寫測試代碼時候拨与,發(fā)現(xiàn)比較元素從 vector<int *>
改為 vector<int>
稻据,比較函數(shù)同樣錯誤的寫為 >=
,運行程序并不會 core买喧,但是打印比較好的數(shù)據(jù)捻悯,發(fā)現(xiàn)數(shù)據(jù)錯了!淤毛!坑爹啊今缚,這樣的坑更深沉。