Вектор сортировки объекта получает исключение переполнения стека c ++ - PullRequest
0 голосов
/ 19 января 2020

Я пытаюсь отсортировать вектор Student объектов по атрибуту:

class Student
{
    private:
        std::string nume;
        int an;
        std::list<Curs> cursuri;
        ...
    public:
        Student();
        Student(std::string nume, int an);
        virtual ~Student();
        ...
};

с этим компилятором метода сортировки:

bool Student::sortByMedie(const Student& a, const Student& b)
{
    return a.medie < b.medie;
}
void sortStudenti(std::vector<Student> studenti) {

    std::sort(studenti.begin(), studenti.end(), Student::sortByMedie);

    for (auto student : studenti) {
        student.afisare();
    }
}

Но я Возникла проблема с исключением переполнения стека при вызове метода сортировки:

Поток 0x4f6 c завершился с кодом 0 (0x0). Возникло исключение 0x776CBA3E (ntdll.dll) в LAB3.exe: 0xC00000FD: переполнение стека (параметры: 0x00000001, 0x01002FF0). Необработанное исключение в 0x776CBA3E (ntdll.dll) в LAB3.exe: 0xC00000FD: переполнение стека (параметры: 0x00000001, 0x01002FF0).

Я предполагаю, что проблема заключается в перераспределении размера вектора в Память. Если я просматриваю трассировку стека за пределами функций выделения памяти, последняя функция моего собственного кода (т. Е. Не стандартной библиотеки) является конструктором копирования Curs, вызываемым перестановкой между двумя элементами Cusr, который вызывается Curs::operator=

Это создание вектора:

    std::vector<Student> studenti;
    auto student1 = Student("gigel marian", 3);
    student1.addCursuri(generateCoursList());
    auto student2 = Student("gigel marian2", 3);
    student2.addCursuri(generateCoursList());
    auto student3 = Student("gigel marian3", 3);
    student3.addCursuri(generateCoursList());
    auto student4 = Student("gigel marian4", 3);
    student4.addCursuri(generateCoursList());
    auto student5 = Student("gigel marian5", 3);
    student5.addCursuri(generateCoursList());

    studenti.push_back(student1);
    studenti.push_back(student2);
    studenti.push_back(student3);
    studenti.push_back(student4);
    studenti.push_back(student5);

Сначала я попробовал этот метод:

void sortStudenti(std::vector<Student> studenti) {
    struct studentCompare
    {
        bool operator()(Student const& a, Student const& b)
        {
            return a.getMedie() > b.getMedie();
        }
    };

    std::sort(studenti.begin(), studenti.end(), studentCompare());

    for (auto student : studenti) {
        student.afisare();
    }
}

, но я получил const ошибки доступа , поэтому я попробовал по-другому.

Редактировать: дополнительный код

Полный код доступен на github

Ответы [ 2 ]

1 голос
/ 19 января 2020

Когда sort() пытается поменять Student элементы, он создает временные копии Student элементов. Поскольку вы ничего не указали, будет выполнена копия по умолчанию для каждого члена.

В вашем классе Student у вас есть список Curs. Список одновременно копируется с элементами Curs, которые он содержит. Но для Curs вы определили свой собственный оператор присваивания:

Curs& Curs::operator=(Curs arg) noexcept
{
    std::swap(*this, arg);
    return *this;
}

Код, который стоит за сгенерированным swap(), заставляет вас снова копировать Curs, что снова вызовет swap и Curs, ... и так до тех пор, пока стек не переполнится или не освободится память.

Кстати, я вижу, что вы создали этот оператор, чтобы обойти ограничения, стоящие за константными членами, содержащимися в классе Curs. Таким образом, обманом компилятора изменить элемент const является неопределенное поведение. Так что избавьтесь от константности для членов, которые нужно скопировать.

Просто избавьтесь от этого (неправильно реализованного) оператора и константы, и все заработает.


Дополнительные рекомендации

Эта проблема действительно сложная, и ее можно решить только с некоторыми фрагментами кода. Особенно, когда проблема не там, где мы думаем. Поэтому я могу порекомендовать вас только в будущем:

Используйте имеющуюся у вас информацию об ошибке в лучшем виде

  • Отправьте свое полное сообщение об ошибке в своем вопросе.
  • В случае переполнения стека: просматривайте трассировку стека, пока не найдете какой-нибудь свой код, чтобы увидеть, в какой части вашего кода он происходит. Это помогает сузить исследование.
  • Если вы просматриваете немного больше, вы также можете проверить, существует ли бесконечная рекурсия (наиболее частая причина переполнения стека при небольшом объеме данных): очень долго последовательность почти идентичных вызовов является типичным симптомом.

Снижение риска ошибок

  • Прежде чем приступить к созданию более сложных классов, проведите тесты, чтобы убедиться, что базовые классы работают должным образом.
  • Даже если у вас недостаточно времени для написания обширных тестов, вы должны хотя бы попробовать каждую функцию-член класса. Если бы вы сделали тест, который просто проверяет, работает ли Curs::operator=, вы бы сэкономили вам много дополнительных экспериментов; -)
0 голосов
/ 19 января 2020

Вы можете передать свой вектор по ссылке и без изменения ваших объектов, передав их в ссылку l oop по const, как указано ниже.

Но убедитесь, что функция-член afisare const

void sortStudenti(std::vector<Student>& studenti) {
    struct studentCompare
    {
        bool operator()(Student const& a, Student const& b)
        {
            return a.getMedie() > b.getMedie();
        }
    };


    std::sort(studenti.begin(), studenti.end(), studentCompare());

    for (const auto& student : studenti) {
        student.afisare();
    }
}

Но я думаю, что есть еще одна причина для исключения. Вы должны были проверить свое определение класса

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