簡體   English   中英

C ++排序stl向量失敗(SIGTRAP)

[英]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;
}

GDB SIGTRAP

您的問題源於使用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM