【问题标题】:The difference between initialize a object and assign to an object初始化对象和赋值给对象的区别
【发布时间】:2023-03-23 05:39:01
【问题描述】:

我正在做一些基本的对象练习,我遇到了这个问题。

这个类名为Matrix,我尝试将a7初始化为a2.mutiply(a5)。

但是当我一开始尝试初始化a7时,结果却大不相同, 并稍后将其分配给a2.mutiply(a5)。

我以为这两个代码是一样的,但结果告诉我我错了。

谁能帮我指出问题?

矩阵.h

// This is part of Martax.h codes.

class Matrix {
private:
    double ** data;     
    int row;            
    int col;
public:
    Matrix();  
    Matrix(int, int);  
    Matrix(int, int, double[], int);
    Matrix(const Matrix &); 

    ~Matrix();

    Matrix add(const Matrix &); 
    Matrix multiply(const Matrix &);    
    Matrix transpose();
    void displayData();
};

Matrix::Matrix()
{
    row = 2;
    col = 2;

    data = new double*[2];
    for (int i = 0; i < 2; i++) 
        data[i] = new double[2]{0};
}

Matrix::Matrix(int a ,int b)
{
    row = a;
    col = b;
    data = new double*[row];
    for (int i = 0; i < row; i++)
        data[i] = new double[col]{0};
}

Matrix::Matrix(int a, int b, double c[], int d) 
{
    row = a;
    col = b;
    data = new double*[row];
    int w = 0;
    for (int i = 0; i < row; i++)
        data[i] = new double[col]{0};

    for (int i = 0; i < row; i++) 
        for (int j = 0; j < col; j++)
        {
            if (w<d)
                data[i][j] = c[w];

            w++;
        }
}

Matrix::Matrix(const Matrix &a)
{
    row = a.row;
    col = a.col;
    data = new double*[row];
    for (int i = 0; i < row; i++)
        data[i] = new double[col];

    for (int i = 0; i < row; i++)
        for (int j = 0; j < col; j++)
            data[i][j] = a.data[i][j];
}

Matrix::~Matrix()
{
    for (int i = 0; i < row; i++)
        delete[] data[i];

    delete[] data;
}

Matrix Matrix::add(const Matrix &a)
{
    static Matrix a5(row,col);
    for (int i = 0; i < row; i++)
        for (int j = 0; j < col; j++)
            a5.data[i][j]=data[i][j] + a.data[i][j];

    return  a5;
}
Matrix Matrix::multiply(const Matrix &a)
{
    double *z;
    z = new double[row*a.col]{0};
    int w = 0;
    int u = 0;
    for (int i = 0; i<row; i++) 
    {
        while (a.col>u)
        {
            for (int j = 0; j < col; j++)
                z[w]+=(data[i][j])*(a.data[j][u]);  

            w++;
            u++;
        }
        u = 0;
    }

    return  Matrix(row,a.col, z, row*a.col);          
}
Matrix Matrix::transpose()
{
    double *z;
    z = new double[row*col];
    int w = 0;
    for (int j = 0; j< col; j++)
        for (int i = 0 ; i < row; i++)
        {
            z[w] = data[i][j];
            w++;
        }

    return  Matrix(col,row,z,row*col);
}
void Matrix::displayData() 
{
    for (int i = 0; i < row; i++) 
    {
        for (int j = 0; j < col; j++) 
           cout << setw(3) << data[i][j];
        cout  << endl;
    }
}

源.cpp

#include<iostream>
#include "Matrix.h"
using namespace std;
int main()
{
    double c[4] = { 1,2,3,4 };
    Matrix a2(2, 2, c, 4);

    Matrix a5(2, 4, d, 8);

    Matrix a7 = a2.multiply(a5);


    cout << "a2 -->";
    a2.displayData();

    cout << "a5 -->";
    a5.displayData();

    cout << "a7 -->";
    a7.displayData();

    a7 = a2.multiply(a5);
    cout << "a7 -->";
    a7.displayData();

    system("pause");
    return 0;
}

结果.txt

"Source.cpp.exe"
Process started (PID=12908) >>>
a2 -->row = 2, column = 2
  1  2
  3  4
a5 -->row = 2, column = 4
  1  2  1  2
  1  2  1  2
a7 -->row = 2, column = 4
  3  6  3  6
  7 14  7 14
a7 -->row = 2, column = 4
<<< Process finished (PID=12908). (Exit code -1073741819)
================ READY ================

【问题讨论】:

  • 添加一点关于三规则的注释:Matrix 没有定义赋值运算符,因此编译器生成一个。编译器生成的赋值运算符复制data 指针,因此您有两个具有相同指针的对象。这些对象中的每一个都将在其析构函数中清理该数据。当第二个析构函数运行时,会发生不好的事情。

标签: c++ class operator-overloading copy-assignment move-assignment-operator


【解决方案1】:

程序具有未定义的行为,因为您没有明确定义复制赋值(或移动赋值)运算符。

这句话之后

a7 = a2.multiply(a5);

由表达式a2.multiply(a5) 创建的临时对象将被销毁。因此,将调用运算符 delete 来获取分配给对象a7 的指针副本。此外还有内存泄漏,因为对象a7的原始指针没有被删除。

您需要明确定义复制赋值运算符或移动赋值运算符或两者。

【讨论】:

  • 嗯,我知道Matrix a1(a2) 是复制构造函数,但Matrix a7 = a2.mutiply(a5) 也是复制构造函数吗?我认为这个会创建一个临时对象并将其分配给a7,并导致相同的结果(临时对象被破坏),但为什么不会发生呢?
  • @JstMonika 创建对象时,将调用复制构造函数。当一个对象已经创建时,就会调用复制赋值运算符。
猜你喜欢
  • 1970-01-01
  • 2013-05-07
  • 2019-11-16
  • 2013-02-11
  • 1970-01-01
  • 2021-10-25
  • 1970-01-01
  • 1970-01-01
  • 2012-11-23
相关资源
最近更新 更多