2015-10-22 94 views
1

我嘗試相對簡單的任務 - 創建一個向量並對其進行排序。但不幸的是,當從堆棧中銷燬載體時,SIGTRAP失敗。當我刪除這種類型時,它確定,但我更需要它。C++排序stl向量失敗(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; 
} 

GDB SIGTRAP

+0

對於一次[此](http://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-認爲是錯誤的),我懷疑你真的想要截斷整數除法'c /(v + 1)'。如果環路是導致錯誤的問題(肯定是錯誤的),請告訴我,以便我可以關閉它。 –

回答

2

眼前的問題 - 導致SIGTRAP - 是您比較操作:

bool operator < (const Vec& oth) const 
{ 
    return !(pomer < oth.pomer); 
} 

它實現爲 「! <」,這是>=,所以回報true平等元素。如果std::sort要使用相同元素,則operator<不得返回true。要求總結爲here。你可以改爲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); 
    } 
} 
+0

就是這樣。謝謝您的幫助。最後,我知道如何安全地從流中讀取數據,而我一直都是錯誤的。 – zbycz

2

您的問題,使用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(NaN不遵循嚴格的弱排序,如std::sort的比較運算符所要求),那麼它也將失敗(完全)。

+0

這也是非常有幫助的,會用它作爲未來的參考。但主要問題是@TonyD指出。 – zbycz

0

好的,問題是veci[i].pomer = c/(v+1);分配到兩個int s的浮動變量divison,因此解決方案是使用pomer = float(c)/(v+1)

不過,我認爲原始代碼應該只是不正確地排序。我不明白爲什麼它完全失敗,特別是在矢量的desctrutor ...任何人?

//編輯:我不知道它爲什麼現在的作品。但是@Jerry Coffin回答說,這個問題可能會與流有關。我會稍後做出反應。

+0

好的一面:意想不到的整數部分可能已經創建了許多相同的'pomer'值,這反過來又導致'operator <'(見我的答案)中的錯誤變得相關。 –