sort () на векторе объектов класса дает ошибку сегментации - PullRequest
0 голосов
/ 22 февраля 2019

Я сталкиваюсь с этой странной проблемой, которая оставила меня без понятия, и я не могу выяснить проблему.Ниже приводится постановка задачи.

В соревнованиях участвуют 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 isопределенно получаю неверный указатель, но мне интересно, почему?

EDIT

Вот скомпилированная версия: https://ideone.com/bcnmE0 с вводом образца.

Ответы [ 2 ]

0 голосов
/ 22 февраля 2019

Как уже было сказано, необходимо, чтобы функция сравнения соответствовала требованиям для Сравнение .Кроме того, ваша функция сравнения не учитывала название команды, когда сравнивались другие поля.Я взял бит из вашего примера @ 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;
}
0 голосов
/ 22 февраля 2019

Ваша функция сравнения неверна.Функции сравнения должны возвращать значение true, если первый параметр «меньше» второго параметра.Но ваш возвращает true (при прочих равных условиях), если t1->active - true.Это означает, что ваша функция может вернуть true для двух команд, которые равны (если бы обе имели active как истину).Неправильные функции сравнения могут привести к сбою алгоритмов сортировки.Попробуйте вместо этого

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 для двух равных команд.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...