简体   繁体   中英

sort() on a vector of class objects gives segmentation fault

I am facing this wierd problem which has left me with no clue and I am not able to figure out the issue. Below is the problem statement.

There are 100 teams participating (numbered 1 to 100) in a competition trying to solve 9 problems. A team may not be able to solve any problem, in which case the total_solved problems and total_time will be zero. For the sake of easiness, I am maintaining a static vector with size as 100. The name stores the team number (1 to 100) . I am using active flag to know that a team submitted at least 1 solution (even wrong).

Here is the class 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;
                }
        }
};

Here is the vector:

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

Somewhere later, I fill the data about the teams. Here is the dump of the data corresponding to these teams :

                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

You can see that no team has solved any problem in this specific case. And some teams are not active (did not submit any solution, name as -1 or active as false denotes that). The crash happens when I try to sort this 100 team data. The sorting criteria is that teams must solve max problems in min time. If there is a tie, we will sort as per team number ignoring the inactive ones.

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);

I analysed through gdb, I get the following :

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 is definitely getting invalid pointer, but I wonder why?

EDIT

Here is the compilable version : https://ideone.com/bcnmE0 with sample input.

Your comparison function is incorrect. Comparison functions should return true if the first parameter is 'less than' the second parameter. But yours returns true (all other things being equal) if t1->active is true. This means your function could return true for two teams which are equal (if both had active as true). Incorrect comparison functions can cause sorting algorithms to crash. Try this instead

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

or this

        return t1->active < t2->active;

Either way you return false for two equal teams.

As already described, you need to make your comparison function meet the requirements for Compare . In addition to that, your comparison function did not take the team name into consideration when the other fields compared equal. I took bits from your example @ ideone and made a MCVE out of it with the bugs fixed:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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