类对象向量上的sort()给出分段错误

时间:2019-02-22 08:06:59

标签: c++ c++11

我正面临着这个棘手的问题,这使我毫无头绪,也无法弄清这个问题。下面是问题陈述。

有100支球队参加比赛(编号1至100),试图解决9个问题。团队可能无法解决任何问题,在这种情况下,total_solved问题和total_time将为零。为了简便起见,我维护一个大小为100的静态向量。name存储组号(1到100)。我使用active标志来知道一个团队至少提交了1个解决方案(甚至是错误的)。

这是team类:

class team
{
public:
        int total_solved;
        int time[9];
        int total_time;
        bool solved[9];
        bool active;
        int name;

        team()
        {
                total_solved = total_time = 0;
                active = false;
                name = -1;
                for(int i=0;i<9;i++)
                {
                        solved[i] = false;
                        time[i] = 0;
                }
        }
};

这是向量:

for(int i=0;i<100;i++)
{
    record.push_back(new team());
}

稍后,我将填充有关团队的数据。这是与这些团队相对应的数据转储:

                cout << "Dumping the data\n";
                for(auto it=record.begin();it!=record.end();it++)
                {
                        cout << (*it)->name << " " << (*it)->total_solved << " " << (*it)->total_time << " " << ((*it)->active?'Y':'N') << endl;
                }
                cout << "That's all\n";

Dumping the data
-1 0 0 N
2 0 0 Y
-1 0 0 N
-1 0 0 N
5 0 0 Y
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
24 0 0 Y
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
34 0 0 Y
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
41 0 0 Y
-1 0 0 N
-1 0 0 N
-1 0 0 N
45 0 0 Y
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
58 0 0 Y
-1 0 0 N
-1 0 0 N
-1 0 0 N
62 0 0 Y
-1 0 0 N
64 0 0 Y
-1 0 0 N
-1 0 0 N
67 0 0 Y
-1 0 0 N
69 0 0 Y
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
78 0 0 Y
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
That's all

您可以看到,在这种特定情况下,没有团队可以解决任何问题。而且有些团队不活跃(未提交任何解决方案,name为-1或active为false表示)。当我尝试对这100个团队数据进行排序时,发生崩溃。排序标准是团队必须在最短的时间内解决最大的问题。如果有平局,我们将根据团队编号进行排序,而忽略不活动的团队。

bool compare(team *t1, team *t2)
{
        if(t1->total_solved != t2->total_solved)
                return t1->total_solved > t2->total_solved;
        if(t1->total_time != t2->total_time)
                return t1->total_time < t2->total_time;
        return t1->active;
}

sort(record.begin(),record.end(),compare);

我通过gdb分析,得到以下信息:

Program received signal SIGSEGV, Segmentation fault.
0x00005555555552d0 in compare (t1=0x55555576fec0, t2=0x411) at 10258.cpp:33
33              if(t1->total_solved != t2->total_solved)

t2肯定得到了无效的指针,但是我想知道为什么吗?

编辑

这是可编译的版本:https://ideone.com/bcnmE0,带有示例输入。

2 个答案:

答案 0 :(得分:5)

您的比较功能不正确。如果第一个参数“小于”第二个参数,则比较函数应返回true。但是,如果t1->active为true,则您的返回true(在所有其他条件相同的情况下)。这意味着对于两个相等的团队,您的函数可能返回true(如果两个团队的active为true)。不正确的比较功能可能会导致排序算法崩溃。试试这个

bool compare(team *t1, team *t2)
{
        if(t1->total_solved != t2->total_solved)
                return t1->total_solved > t2->total_solved;
        if(t1->total_time != t2->total_time)
                return t1->total_time < t2->total_time;
        return t1->active > t2->active;
}

或这个

        return t1->active < t2->active;

无论哪种方式,对于两个相等的团队,您都返回false。

答案 1 :(得分:0)

如上所述,您需要使比较功能满足Compare的要求。除此之外,当其他字段比较相等时,您的比较功能未考虑团队名称。我从您的示例@ ideone中获取了一些信息,并通过修复以下错误从其中制作了MCVE:

#include <iostream>
#include <vector>
#include <algorithm>
#include <memory>
#include <array>

class team {
public:
    int total_solved;
    std::array<int, 9> time;
    int total_time;
    std::array<bool, 9> solved;
    bool active;
    int name;

    team(int Name) :
        total_solved{0},
        time{},
        total_time{0},
        solved{},
        active{false},
        name(Name)
    {}

    inline bool operator<(team const& t2) const {
        if(total_solved != t2.total_solved)
            return total_solved > t2.total_solved;
        if(total_time != t2.total_time)
            return total_time < t2.total_time;
        // return t1->active;          // bug
        if(active != t2.active)        // bug-fix
            return active > t2.active; //   -"-
        // the below was specified as the last sorting criteria
        // but wasn't included in your actual code:
        return name < t2.name;
    }

    friend std::ostream& operator<<(std::ostream&, const team&);
};

std::ostream& operator<<(std::ostream& os, const team& t) {
    os << t.name << " " << t.total_solved << " "
       << t.total_time << " " << (t.active?"Y":"N") << "\n";
    return os;
}

int main() {
    // bug-fix: making sure the teams are deleted using std::unique_ptr
    std::vector<std::unique_ptr<team>> record;

    for(int i=1; i<=100; ++i)
        record.emplace_back(new team(i));

    for(auto contestant : {41,67,34,2,69,24,78,58,62,64,5,45})
        record[contestant-1]->active = true;

    std::cout << "Dumping the data\n";
    for(auto& t : record) std::cout << *t;

    std::sort(record.begin(), record.end(),
        [](std::unique_ptr<team> const& a, std::unique_ptr<team> const& b) {
            return *a < *b;
        }
    );

    std::cout << "After sort\n";
    for(auto& t : record) std::cout << *t;
}