【问题标题】:Sort vector of object receive stack overflow exception c++对象的排序向量接收堆栈溢出异常c ++
【发布时间】:2020-05-05 15:52:04
【问题描述】:

我正在尝试按属性对 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 方法时遇到了堆栈溢出异常的问题:

线程 0x4f6c 以代码 0 (0x0) 退出。在 LAB3.exe 中的 0x776CBA3E (ntdll.dll) 处引发异常:0xC00000FD:堆栈溢出(参数:0x00000001、0x01002FF0)。 LAB3.exe 中 0x776CBA3E (ntdll.dll) 处未处理的异常:0xC00000FD:堆栈溢出(参数:0x00000001、0x01002FF0)。

我假设问题出在内存中向量大小的重新分配中。如果我浏览内存分配函数之外的堆栈跟踪,我自己的代码(即不是标准库)的最后一个函数是 Curs 复制构造函数,由两个 Cusr 元素之间的交换调用,由 @987654330 调用@

这是向量的创建:

    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获取

【问题讨论】:

  • @Grandin98 您还通过值而不是引用循环遍历 studenti 向量,这意味着您正在对复制的对象调用 afisare 函数。见stackoverflow.com/questions/15927033/…
  • 为什么你通过值而不是通过引用传递向量? stackoverflow.com/questions/26647152/…
  • 关于堆栈溢出异常可能与您的 Student 类以及它如何处理复制有关。
  • @EyalD 我没有将向量作为参考传递,因为我不想修改原始列表
  • 无法重现 stackoverflow 异常。发布类定义本身

标签: c++ sorting vector stl std


【解决方案1】:

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 成员背后的限制。以这种方式欺骗编译器来更改 const 元素是未定义的行为。所以摆脱需要复制的成员的常量。

只要去掉这个(错误实现的)运算符和常量,它就可以工作了。


其他建议

这个问题确实是一个复杂的问题,只需提取一些代码即可处理。尤其是当问题不在我们认为的地方时。所以我只能在以后推荐你:

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

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

降低出错风险

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

【讨论】:

  • 干得好,我什至无法编译该代码(minGW g++)。为了至少进行编译,我完全删除了该运算符重载函数。甚至无法想象这是原因
【解决方案2】:

您可以通过引用传递您的向量,而无需通过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();
    }
}

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

【讨论】:

  • 此答案与题头中指定的问题无关
  • @mangusta 提问者希望通过引用传递对象而不更改它们以避免复制!!。请参阅有关问题的 cmets。
猜你喜欢
  • 1970-01-01
  • 2010-10-30
  • 2010-11-27
  • 2010-12-08
  • 2020-11-14
相关资源
最近更新 更多