[英]C++ sorting stl vector fails (SIGTRAP)
我嘗試相對簡單的任務-創建矢量並將其排序。 但是不幸的是,當從堆棧中銷毀向量時,它因SIGTRAP而失敗。 當我刪除排序時,它還可以,但是我更需要它。
我已將問題縮小到最小的源代碼。 當我運行它時,我得到Windows錯誤“程序意外停止”。 當我使用附加的GDB時,它會在完成第一個while循環后突出顯示向量析構函數。 (見下圖)
我都嘗試過vector<Vec> veci(n);
並resize(n)
。 我感覺到它可能是由排序算法引起的,該排序算法以某種方式對向量中不存在的項目進行了排序,但是代碼並未指出問題……您看到了嗎?
Windows 10,MinGW GCC
#include <stdio.h>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <ctime>
#include <stack>
#include <vector>
#include <algorithm>
#include <numeric>
#include <string>
#include <sstream>
using namespace std;
struct Vec {
int cena;
int vaha;
float pomer;
bool operator < (const Vec& oth) const
{
return !(pomer < oth.pomer);
}
};
int main(int argc, char** argv) {
stringstream file;
file << "9550 40 600 14 223 38 230 3 54 1 214 13 118 4 147 15 16 2 104 5 56 49 154 40 106 24 234 18 34 33 195 7 74 10 129 12 159 42 37 41 10 11 185 6 243 45 87 32 57 20 87 9 26 16 201 39 0 23 128 39 194 21 10 46 1 8 28 30 59 26 130 35 160 22 91 34 180 19 16 31 1 17 72";
while (file.good()) {
int id;
int n;
int M;
file >> id;
file >> n;
file >> M;
vector<Vec> veci;
veci.resize(n);
for (int i = 0; i < n; i++) {
int c, v;
file >> v;
file >> c;
veci[i].vaha = v;
veci[i].cena = c;
veci[i].pomer = c / (v+1);
}
sort(veci.begin(), veci.end());
}
printf("end");
return 0;
}
您的問題源於使用while (file.good())
,這實際上總是一個錯誤(在這種情況下)。
這不會檢測到文件結尾是否正確,並且最終將最后一項寫入向量兩次,但是您只為將它寫入一次留出了空間,因此這會超出分配空間的結尾。
當排序嘗試使用現在已損壞的堆上的數據時,您開始發現問題。
糾正是相當瑣碎的:正確讀取數據,例如:
#include <stdio.h>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <ctime>
#include <stack>
#include <vector>
#include <algorithm>
#include <numeric>
#include <string>
#include <sstream>
#include <iterator>
using namespace std;
struct Vec {
int cena;
int vaha;
float pomer;
bool operator < (const Vec& oth) const {
return !(pomer < oth.pomer);
}
friend std::istream &operator>>(std::istream &is, Vec &v) {
return is >> v.vaha >> v.cena >> v.pomer;
}
friend std::ostream &operator<<(std::ostream &os, Vec const &v) {
return os << "{" << v.vaha << ", " << v.cena << ", " << v.pomer << "}";
}
};
int main(int argc, char** argv) {
stringstream file;
file << "9550 40 600 14 223 38 230 3 54 1 214 13 118 4 147 15 16 2 104 5 56 49 154 40 106 24 234 18 34 33 195 7 74 10 129 12 159 42 37 41 10 11 185 6 243 45 87 32 57 20 87 9 26 16 201 39 0 23 128 39 194 21 10 46 1 8 28 30 59 26 130 35 160 22 91 34 180 19 16 31 1 17 72";
std::vector<Vec> veci { std::istream_iterator<Vec>(file), std::istream_iterator<Vec>{ } };
sort(veci.begin(), veci.end());
std::copy(veci.begin(), veci.end(), std::ostream_iterator<Vec>(std::cout, "\n"));
return 0;
}
最后一點:比較功能的作用與大多數人的預期相反。 如果您在結構的pomer
字段中輸入NaN(也不會完全遵循比較運算符對std::sort
要求,NaN不會遵循嚴格的弱排序),它也會(完全)失敗。
引起SIGTRAP的直接問題是您的比較運算符:
bool operator < (const Vec& oth) const
{
return !(pomer < oth.pomer);
}
它實現為“ ! <
”,即>=
,因此對於相等的元素返回true
。 如果std::sort
要使用operator<
絕對不能對相等的元素返回true
。 要求總結在這里 。
您可以改為說return power > oth.pomer
。
請注意, file.good()
在您的情況下可以正常工作,因為在解析最終的72值之后,沒有空格,並且該int
提取將通過eof
終止,從而影響流狀態。 但是,它非常脆弱,因為流狀態在任何時間點都是良好的,所以您可以假定將來的流操作可以正常工作。 最好在信任嘗試流入的變量之前先測試流狀態是否仍然良好,尤其是在執行諸如resize
然后進行數組索引之類的操作時。
更強大的I / O的示例:
#define ASSERT(X, MSG) \
do { \
if (!(X)) { \
std::cerr << "ASSERT fail @" << __LINE__ \
<< " !(" #X ") " << MSG << "\n"; \
exit(EXIT_FAILURE); \
} \
} while (false)
while (file >> skipws && file.good())
{
int id;
int n;
int M;
ASSERT(file >> id >> n >> M, "unable to read 'id n m' fields");
vector<Vec> veci;
veci.resize(n);
for (int i = 0; i < n; i++) {
int c, v;
ASSERT(file >> v >> c,
"unable to read 'c v' fields for [" << i << ']');
ASSERT(v + 1 != 0, "'v' value would trigger divide by zero");
veci[i].vaha = v;
veci[i].cena = c;
veci[i].pomer = c / (v+1);
}
}
好的,問題出在veci[i].pomer = c / (v+1);
分配給兩個int
的float變量pomer = float(c) / (v+1)
,因此解決方案是使用pomer = float(c) / (v+1)
。
不過,我認為原始代碼應該排序不正確。 我不明白為什么它會完全失敗,尤其是在vector的描述符上……有人嗎?
// edit:我不知道為什么現在可以使用。 但是問題可能是@Jerry Coffin回答的。 稍后我會回應。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.