简体   繁体   English

析构函数导致程序崩溃

[英]Destructor causes the program to crash

I am really struggling with the concept of using destructors with copy constructors. 我真的在将析构函数与复制构造函数一起使用的概念感到困惑。 If I don't use a destructor the code works fine, as it does it automatically. 如果我不使用析构函数,则代码会正常工作,因为它会自动执行。 If I do, I get an error saying 'Debug Assertion Failed!' 如果这样做,我会收到一条错误消息,提示“调试断言失败!”。 and 'Expression:_BLOCK_TYPE_IS_VALID(pHead->nBlockUse). 和'Expression:_BLOCK_TYPE_IS_VALID(pHead-> nBlockUse)。

But I want to be able to understand how to use destructors. 但是我希望能够了解如何使用析构函数。 Here is the code below, I would very much appreciate help explaining what I have done incorrectly or need to do! 这是下面的代码,非常感谢您帮助解释我做错或需要做的事情!
class Matrix { 类矩阵{

private:
    int M;
    int N;
    double *data;

public:
    Matrix();
    int getM() const { return M; }
    int getN() const { return N; }

    //CONSTRUCTOR
    Matrix(int sizeR, int sizeC,double * input_data)
    {
        M = sizeR; //Rows
        N = sizeC; //Columns

        data = new double[M*N]; //creation of 1D array, uses m&n values

        cout << "\nMatrix::Matrix(int sizeR, int sizeC, double * data_value) is invoked...\n\n";

        //ENTER DATA INTO MATRIX HERE:
        for(int i=0; i < M*N; i++) //Loops for every data entry into 1D array, uses r&c as referenece to
            data[i] = input_data[i];//Accesses each value at specific location, inputs value 'val'
        for(int i = 0; i < M*N; i++) //Loops for every data entry into 1D array, uses r&c as referenece to size
            cout << data[i] << " ";
    }

    //get function uses row and column from user
    double get(int i, int j)
    {
        return data[i*N+j];
    }

    double set(int i, int j, double val)
    {
        data[i*N+j] = val;

        cout << "\n\nNEW MATRIX: ";
        for(int i = 0; i < M*N; i++)//Loops for every data entry into 1D array, uses r&c as referenece to size
            cout << data[i] << " ";

        return val;
    }

    Matrix(const Matrix& oldMatrix)
    {
        cout¸<< "\nMatrix::Matrix(const Matrix&) is invoked....";
        M = oldMatrix.getM();
        N = oldMatrix.getN();
        data = oldMatrix.data;

        cout << "\n\n";

        //ENTER DATA INTO MATRIX HERE:

        for(int i = 0; i < M*N; i++)//Loops for every data entry into 1D array, uses r&c as referenece to size
            cout << data[i] << " ";

    }

    //DESTRUCTOR
    ~Matrix()
    {
        //delete data
        delete [] data;
        data = NULL;
        cout << "\n\nMatrix::~Matrix() is invoked...\n\n";
    }



};

int main()
{
    int sizeR, sizeC;
    double val;

    cout << "Enter No. Rows: ";
    cin >> sizeR;

    cout << "Enter No. Columns: ";
    cin >> sizeC;

    double * input_data;


    input_data = new double[sizeR*sizeC];

    //INPUTS VALUES TO ARRAY
    for(int i = 0; i < sizeR*sizeC; i++)//Loops for every row
        input_data[i] = i;

    Matrix M1(sizeR, sizeC, input_data);

    cout << "Enter row that value you are after is in: ";
    cin >> sizeR;
    cout << " & now the column that it is in: ";
    cin >> sizeC;


    cout << "Change value: " << M1.get(sizeR, sizeC) << " to:";
    cin >> val;
    M1.set(sizeR, sizeC, val);

    //calls copy constructor
    M1 = Matrix(M1);
}

In the copy-constructor you copy the pointer , meaning you you now have two objects both having the same pointer. 在复制构造函数中,您将复制指针 ,这意味着您现在拥有两个具有相同指针的对象。 If one of those objects are destructed, then it leaves the other object with a now invalid pointer. 如果这些对象之一被破坏,那么它将使另一个对象现在具有无效的指针。

Dereferencing this pointer in anyway, or attempting to free it, will lead to undefined behavior . 无论如何取消引用该指针或尝试释放它,都将导致未定义的行为

The problematic line in question is this one: 有问题的一行是这一行:

M1 = Matrix(M1);

That line creates a temporary object, and copies the data from M1 into that temporary object, then it assigns the temporary object back to M1 (and the compiler-generated copy-assignment operator will just do a shallow copy of the members, so not much different from your copy-constructor) and then destruct the temporary object, leading to the stray and invalid pointer in M1 . 该行创建一个临时对象,然后将数据从M1复制到该临时对象中,然后将临时对象分配回M1 (并且编译器生成的复制分配运算符将对成员进行浅表复制,因此不需要太多操作(与复制构造函数不同),然后破坏临时对象,导致M1的杂散指针和无效指针。


On a slightly related issue, you also might want to learn about the rule of three . 在一个稍微相关的问题上,您可能还想了解三个规则

You are copying a pointer of one object into another inside the Copy constructor: 您正在将一个对象的指针复制到Copy构造函数中的另一个对象中:

Matrix(const Matrix& oldMatrix)
{
   ...
   data = oldMatrix.data;

After calling the copy constructor you have two objects referring to the same memoryblock. 调用复制构造函数后,您将拥有两个引用同一内存块的对象。 And if one object is destroyed the memory block is deleted and the second object points to an invalid memory location. 如果一个对象被破坏,则删除存储块,第二个对象指向无效的存储位置。

In the copy constructor you also need to allocate a new buffer! 在复制构造函数中,您还需要分配一个新缓冲区!

A solution could be adding a bool variable ( is_copy for instance) to your Matrix class. 一种解决方案是在您的Matrix类中添加一个布尔变量(例如is_copy )。 Set it to false on constructor and to true on copy constructor. 在构造函数上将其设置为false,在复制构造函数上将其设置为true。 Only deallocate memory in destructor if is_copy is false. 如果is_copy为false,则仅在析构函数中释放内存。

Or, as suggested in the comments, better use a smart pointer. 或者,如注释中所建议,最好使用智能指针。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM