对象的排序向量接收堆栈溢出异常C++

Sort vector of object receive stack overflow exception c++

我正在尝试按属性对 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();
    }
}

但是调用sort方法时遇到堆栈溢出异常的问题:

The thread 0x4f6c has exited with code 0 (0x0). Exception thrown at 0x776CBA3E (ntdll.dll) in LAB3.exe: 0xC00000FD: Stack overflow (parameters: 0x00000001, 0x01002FF0). Unhandled exception at 0x776CBA3E (ntdll.dll) in LAB3.exe: 0xC00000FD: Stack overflow (parameters: 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

您可以通过引用传递您的向量,而不更改您的对象,方法是通过 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();
    }
}

但我认为还有一个例外的原因。你应该检查你的class定义

sort() 尝试交换 Student 元素时,它会制作 Student 元素的临时副本。由于您没有指定任何其他内容,因此将执行默认的逐个成员复制。

在您的 Student class 中,您有一个列表 Curs。该列表与它包含的 Curs 元素一起复制。但是对于 Curs,您已经定义了自己的赋值运算符:

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

生成的 swap() 后面的代码让您再次复制 Curs,这将再次调用交换和 Curs,....等等,直到堆栈溢出或内存用完。

顺便说一句,我看到您创建此运算符是为了规避 Curs class 包含的 const 成员背后的限制。以这种方式欺骗编译器来更改 const 元素是未定义的行为。因此,摆脱需要复制的成员的常量。

只需摆脱这个(错误实现的)运算符和常量,它就会起作用。


其他建议

这个问题确实是一个复杂的问题,只需要摘录一些代码就可以解决。特别是当问题不在我们认为的地方时。所以以后只能推荐你了:

充分利用您掌握的错误信息

  • Post 您问题中的完整错误消息。
  • 在堆栈溢出的情况下:浏览堆栈跟踪,直到找到您的一些代码,看看它发生在代码的哪一部分。这有助于缩小研究范围。
  • 如果你多浏览一点,你还可以检查是否存在无限递归(数据量小的堆栈溢出最常见的原因):很长的连续几乎相同的调用是一个典型的症状.

减少出错的风险

  • 在开始构建更复杂的 classes 之前,进行测试以确保底层 classes 能够按预期工作。
  • 即使您没有足够的时间编写大量测试,您也应该至少尝试每个 class 成员函数。如果你做了一个只检查 Curs::operator= 是否有效的测试,你就会节省很多额外的实验;-)