【问题标题】:Copying a dynamic array and deleting the original using an overloaded operator使用重载运算符复制动态数组并删除原始数组
【发布时间】:2018-02-08 16:19:27
【问题描述】:

我正在创建一个跟踪学生的课程。在这个类中,我使用重载的 = 来复制这些学生对象。为了跟踪他们的课程,我使用了一个动态数组。数组复制得很好;但是,当清除学生对象的变量时,之前从该对象复制的任何对象也会擦除其数组。代码如下:

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

class Student
{
    string name;                //Name
    string* classList = NULL;   //Empty array to store class names in
    int numClasses = 0;         //Number of classes

public:
    void InputData()
    {
        cout << "Enter student name: " << endl;                         //Input Name
        cin >> name;
        cout << "Enter number of classes: " << endl;                    //Input classes
        cin >> numClasses;

        classList = new string[numClasses];                             //Define array size
        for (int i = 0; i < numClasses; i++)                            //For every spot in array, name class
        {
            cout << "Enter name of class " << (i + 1) << ":" << endl;   //Name class
            cin >> classList[i];
        }

    };

    void OutputData()
    {
        cout << "Name: " << name << endl;                               //Output data
        cout << "Number of Classes: " << numClasses << endl;
        for (int i = 0; i < numClasses; i++)                            //Cycle through and output classes
        {
            cout << "Class " << i << ": " << classList[i] << endl;
        }
    };

    void ResetClasses()
    {
        name = "";
        delete[] classList;         //Free Memory
        classList = NULL;           //Clear array
        numClasses = 0;
    };

    Student operator =(Student& student)                //Overload =
    {
        this->name = student.name;
        this->classList = student.classList;
        this->numClasses = student.numClasses;
        return *this;
    };
};

int main()
{
    Student s1, s2;

    s1.InputData();               // Input data for student 1
    cout << "Student 1's data:" << endl;
    s1.OutputData();              // Output data for student 1

    s2 = s1;
    cout << "Student 2's data after assignment from student 1:" << endl;
    s2.OutputData();              // Should output same data as for student 1

    s1.ResetClasses();
    cout << "Student 1's data after reset:" << endl;
    s1.OutputData();              // Should have no classes

    cout << "Student 2's data, should still have original classes:" << endl;
    s2.OutputData();              // Should still have original classes
}

主要的罪犯几乎可以肯定是这两个中的任何一个

        void ResetClasses()
        {
            name = "";
            delete[] classList;         //Free Memory
            classList = NULL;           //Clear array
            numClasses = 0;
        };

        Student operator =(Student& student)                //Overload =
        {
            this->name = student.name;
            this->classList = student.classList;
            this->numClasses = student.numClasses;
            return *this;
        };

程序的输出是:

Enter student name:
ERIC
Enter number of classes:
2
Enter name of class 1:
C++
Enter name of class 2:
C
Student 1's data:
Name: ERIC
Number of Classes: 2
Class 0: C++
Class 1: C
Student 2's data after assignment from student 1:
Name: ERIC
Number of Classes: 2
Class 0: C++
Class 1: C
Student 1's data after reset:
Name:
Number of Classes: 0
Student 2's data, should still have original classes:
Name: ERIC
Number of Classes: 2
Class 0:
Class 1:

我做错了什么会导致这种情况?

【问题讨论】:

  • 使用向量而不是原始指针,你会摆脱你的问题。目前您有 2 个具有相同指针的对象。
  • 停止疯狂,使用std::vector&lt;std::string&gt;
  • 如果 2 个 cmets 已经这样说还不够,您应该使用 vector&lt;string&gt;。不是原始数组和原始指针之类的东西。
  • this->classList = student.classList;是错的。请创建类列表的深层副本。当前解决方案的问题是,当您重置类时,它将释放内存,但另一个类正在使用相同的指针。这就是为什么你需要深拷贝。另一个与崩溃无关的错误是 operator= 应该返回 ref,即 student& 而不是 student。但正如其他人提到的,使用向量
  • 要纠正您的代码的所有问题,您的代码中缺少主要部分(例如@SamVarshavchik 指出的)。 IMO 最好see a small example 这些操作以及您所缺少的..

标签: c++ arrays object dynamic operator-overloading


【解决方案1】:

您需要创建班级列表的副本,否则两个学生对象将有一个指向内存中相同位置的字段。

释放这些字段之一将导致另一个也被释放。

在您的复制构造函数和赋值运算符中,为新对象创建一个大小相同的新数组,然后将每个元素复制到新对象。

【讨论】:

  • 或者简单地使用已经实现的 - std::vector&lt;std::string&gt; 就像 @ArtemyVysotsky 建议的那样。
  • 那肯定是更好的解决方案,但我将把这个答案留在这里,因为它解释了 OP 最初遇到的问题。
  • 不要使用memcpy——它不能使用std::string作为类型。
【解决方案2】:
Student operator =(Student& student)

赋值运算符应采用const 引用参数。赋值运算符也应该返回一个引用,而不是一个值。

这个类也缺少一个拷贝构造函数。

在赋值运算符中:

this->classList = student.classList;

这是一个普通的指针。首先,这是内存泄漏。前一个指针(如果有的话)丢失,分配的内存泄漏。

现在您有两个具有相同classList 指针的类实例。因此,当在其中一个类上调用 resetClasses() 方法时,它将被删除,并且由于该类的另一个实例具有相同的指针,它现在指向已删除的内存。

您的赋值运算符必须正确删除现有数组(如果有的话),并克隆被赋值的实例中保存的数组(如果有的话)。其中大部分也适用于您必须实现的复制构造函数。

这个类也缺少一个析构函数,这将导致另一个内存泄漏。

您的班级存在所有这些多重基本问题。您必须修复所有这些问题才能使您的课程正常工作。您必须实现正确的复制构造函数、赋值运算符和析构函数,以正确克隆、复制和销毁您的类所持有的数据的实例。

您似乎还没有学会如何使用容器和智能指针,如果您要学习如何正确跟踪分配的内存、避免内存损坏和内存泄漏,那么您的练习的重点是。这显然是一项重要的学习技能;但是,一旦您弄清楚了所有这些,并且您的课程正常工作,您只需将指针替换为 std::vector,就不用再担心了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-04
    相关资源
    最近更新 更多