在 C++ 中使用带有字符串的复制构造函数和/或赋值运算符时堆栈溢出

stack overflow when using copy constructor and/or assignment operator with string in c++

提问人:Russell Butler 提问时间:1/12/2020 最后编辑:Russell Butler 更新时间:1/12/2020 访问量:128

问:

我正在尝试在我自己制作的一个简单的类上运行插入排序,该类具有几个字段(int、float 和 string)以及复制构造函数、赋值运算符和“>”运算符。

但是,当我运行下面的代码时,我得到了堆栈溢出。Visual Studio 告诉我它来自我的“Student”类中的 getName() 函数。 该错误源于我的插入排序函数中的赋值arr[i + 1] = arr[i];

有人知道这是为什么吗?我对 C++ 比较陌生,主要来自 Java 背景。

#include <iostream>
#include <vector>
#include <string>
using namespace std;

class Student {
public:
    Student(string nm, int ID, float avg): name(nm), studentID(ID), overallAverage(avg) {}

    Student(const Student& rhs) : name(rhs.getName()), studentID(rhs.getStudentID()), overallAverage(rhs.getOverallAverage()) {}

    // copy and swap idiom
    Student& operator=(const Student& rhs) {
        Student copy = rhs;  // places a copy of rhs into copy using the copy constructor (copy will be cleaned up on return)
        swap(*this, copy); // move copy or rhs into this, this is a pointer to current object, *this dereferences the pointer
        return *this; 
    }
    ~Student() {}

    bool operator>(const Student& rhs) {
        if (rhs.getOverallAverage() > overallAverage)
            return false;
        else return true; 
    }

    string getName()const { return name; }
    int getStudentID()const { return studentID;  }
    float getOverallAverage()const { return overallAverage; }

private:
    string name; 
    int studentID; 
    float overallAverage; 

};

template<typename T> 
vector<T>& insertionSort(vector<T>& arr){
    for (int j = 1; j < arr.size(); j++) {
        T key = arr[j]; 
        int i = j - 1; 
        while (i > -1 && arr[i] > key) {
            arr[i + 1] = arr[i]; 
            i = i - 1; 
        }
        arr[i + 1] = key; 
    }
    return arr; 
}


int main()
{
    vector<Student> students = {Student("russ",0,89),Student("Seb",1,75),Student("julia",2,85),
                                Student("johnny",3,90),Student("Sushma",4,55)}; 

    students = insertionSort(students); 

    for (int i = 0; i < students.size(); i++) {
        cout << students[i].getName() << ", ";
    }
    cout << endl;  
}

原始运算符= 来自我正在使用的 TXTBOOK :

IntCell & operator= ( const IntCell & rhs ) // Copy assignment
{
IntCell copy = rhs;
std::swap( *this, copy );
return *this;
}
C++ C++11 堆栈溢出 copy-constructor 赋值运算符

评论

2赞 PaulMcKenzie 1/12/2020
你的电话,哪个叫你的,哪个叫你的,哪个叫你的,哪个叫......operator =std::swapoperator =std::swapoperator =std::swap
0赞 Russell Butler 1/12/2020
真?我直接从一本著名的 C++ 教科书中处理了 operator= :edit-> 将教科书的 operator= 放在我原始问题的底部
1赞 PaulMcKenzie 1/12/2020
在那本书中,类有自己的功能吗?如果是这样,那就是阻止无限递归的原因。将使用 class 函数。swapstd::swapswap
0赞 Russell Butler 1/12/2020
啊,我看你是对的。在重读该部分时,它提到:“t。请注意,如果使用图 1.14 中的基本复制算法实现交换,则复制和交换习惯将不起作用,因为将存在相互的非终止递归。在 C++ 11 中,我们有一个基本的期望,即交换是通过三个移动或逐个成员交换来实现的。
0赞 PaulMcKenzie 1/12/2020
像这样的泛型例程要求参数是可交换的,而显然你的类不是,直到创建自定义函数。std::swapStudentStudent::swap

答:

2赞 PaulMcKenzie 1/12/2020 #1

无限递归是由调用 、 调用 、 调用 等引起的。std::swapStudent::operator=std::swapStudent::operator=

为了缓解这种情况,请编写自己的函数来调用每个成员:swapstd::swap

class Student
{
//...
   void swap(Student& left, Student& right)
    {
        std::swap(left.name, right.name);
        std::swap(left.studentID, right.studentID);
        std::swap(left.overallAverage, right.overallAverage);
    }
//...
};

评论

0赞 Russell Butler 1/12/2020
谢谢。它现在起作用了。std::swap 不起作用(错误 - 没有重载函数 std::swap 的实例与参数列表匹配)所以我只是做了 left.name = right.name 等。 这不好吗?
0赞 PaulMcKenzie 1/12/2020
查看 std::swap 期望参数是什么。