简体   繁体   English

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

[英]C++ sorting stl vector fails (SIGTRAP)

i try relatively simple task - create a vector and sort it. 我尝试相对简单的任务-创建矢量并将其排序。 But unfortunately when destroying the vector from stack, it fails with SIGTRAP. 但是不幸的是,当从堆栈中销毁向量时,它因SIGTRAP而失败。 When I remove the sort, its OK, but i rather need it. 当我删除排序时,它还可以,但是我更需要它。

I have narrowed the issue to smallest possible source code. 我已将问题缩小到最小的源代码。 When I run it, i get windows error "Program stopped unexpectedly". 当我运行它时,我得到Windows错误“程序意外停止”。 When i use GDB attached, it highlights the vector destructor after finishing the first while loop. 当我使用附加的GDB时,它会在完成第一个while循环后突出显示向量析构函数。 (See picture below) (见下图)

I have tried both vector<Vec> veci(n); 我都尝试过vector<Vec> veci(n); and resize(n) . resize(n) I sense it could be caused by the sort algorithm somehow sorting items not present in the vector, but the code doesnt indicate the problem... do you see it? 我感觉到它可能是由排序算法引起的,该排序算法以某种方式对向量中不存在的项目进行了排序,但是代码并未指出问题……您看到了吗?

Windows 10, mingw gcc 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

Your problem stems from using while (file.good()) , which is virtually always an error (and is in this case). 您的问题源于使用while (file.good()) ,这实际上总是一个错误(在这种情况下)。

This doesn't detect the end of file correct, and ends up writing the last item to the vector twice--but you've only made room for it to be written there once, so this writes past the end of the allocated space. 这不会检测到文件结尾是否正确,并且最终将最后一项写入向量两次,但是您只为将它写入一次留出了空间,因此这会超出分配空间的结尾。

When the sort attempts to work with the data on the now-corrupted heap, you start to see the problem. 当排序尝试使用现在已损坏的堆上的数据时,您开始发现问题。

The correction is fairly trivial: read the data correctly, such as: 纠正是相当琐碎的:正确读取数据,例如:

#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;
}

One final note: your comparison function works the reverse of what most people expect. 最后一点:比较功能的作用与大多数人的预期相反。 It will also fail (completely) if you end up with a NaN in the pomer field of your struct (NaN's don't follow a strict weak ordering, as required by the comparison operator for std::sort ). 如果您在结构的pomer字段中输入NaN(也不会完全遵循比较运算符对std::sort要求,NaN不会遵循严格的弱排序),它也会(完全)失败。

The immediate problem - causing the SIGTRAP - is your comparison operator: 引起SIGTRAP的直接问题是您的比较运算符:

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

It's implemented as " ! < ", which is >= , so returns true for equal elements. 它实现为“ ! < ”,即>= ,因此对于相等的元素返回true An operator< must never return true for equal elements if it's to be used by std::sort . 如果std::sort要使用operator<绝对不能对相等的元素返回true Requirements are summarised here . 要求总结在这里

You could instead say return power > oth.pomer . 您可以改为说return power > oth.pomer

Note that file.good() works correctly in your case, as after parsing the final 72 value there's no whitespace and extraction of that int will be terminated by eof , affecting the stream state. 请注意, file.good()在您的情况下可以正常工作,因为在解析最终的72值之后,没有空格,并且该int提取将通过eof终止,从而影响流状态。 It's damned fragile though, as is the idea that because the stream state is good at any point in time, you can presume that future streaming operations work. 但是,它非常脆弱,因为流状态在任何时间点都是良好的,所以您可以假定将来的流操作可以正常工作。 It's better to test the stream state's still good at some point before trusting the variables you've attempted to stream into, especially if you're doing something like resize followed by array indexing. 最好在信任尝试流入的变量之前先测试流状态是否仍然良好,尤其是在执行诸如resize然后进行数组索引之类的操作时。

Example of more robust I/O: 更强大的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);
    }
}

Ok, the problem was veci[i].pomer = c / (v+1); 好的,问题出在veci[i].pomer = c / (v+1); assigning to float variable divison of two int s, thus solution is to use pomer = float(c) / (v+1) . 分配给两个int的float变量pomer = float(c) / (v+1) ,因此解决方案是使用pomer = float(c) / (v+1)

Still, i think that the original code should just sort incorrectly. 不过,我认为原始代码应该排序不正确。 I dont understand why it fails completely, especially on vector's desctrutor... Anybody? 我不明白为什么它会完全失败,尤其是在vector的描述符上……有人吗?

//edit: i dont know why it works now. // edit:我不知道为什么现在可以使用。 But problem would be probably with the stream as @Jerry Coffin answered. 但是问题可能是@Jerry Coffin回答的。 I will react later. 稍后我会回应。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM