自定义 Matrix 类中的复制构造函数问题

Issues with copy constructor in custom Matrix class

提问人:Herman Neple 提问时间:3/15/2023 最后编辑:Vlad from MoscowHerman Neple 更新时间:3/15/2023 访问量:70

问:

我有一个自定义矩阵类,它本身就可以正常工作。我遇到的问题是,当我尝试创建由另一个矩阵定义的新矩阵时,不会复制整个矩阵。

矩阵本身基本上只是一个指向一维双精度数组的指针,其中我有一个自定义函数来查找正确的 m x n 索引。 我创建了一个复制构造函数并重载了 = 运算符。我认为只有矩阵的一部分被复制真的很奇怪。

问题可能在于我如何对待我的指针,因为我没有完全掌握它。

当我尝试这样做时:

Matrix m(3,10);

for(int i = 0; i<m.getColumns(); i++){
   m.set(0,i, 4);
}

Matrix l(m);
Matrix c = m;

cout << m << endl;
cout << l << endl;
cout << c << endl;

我得到这个输出:

4 4 4 4 4 4 4 4 4 4 
0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 


4 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 


4 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 

这是我的 Matrix.h 文件:

#pragma once
#include <iostream>

using namespace std;

class Matrix
{
private:
    int r;
    int c;
    int getIndex(int r, int c) const;
    double* matrix;
public:
    Matrix(int nRows, int nColumns);
    explicit Matrix(int nRows);
    Matrix(const Matrix &);
    ~Matrix();
    double get(int row, int col) const;
    void set(int row, int col, double value);
    int getRows() const;
    int getColumns() const;
    friend ostream& operator<<(ostream& os, const Matrix& m);
    Matrix& operator=(Matrix rhs);
}; 

这是类的定义:

#include <Matrix.h>
#include <cassert>
#include <iostream>
#include <utility>

using namespace std;

Matrix::Matrix(int nRows, int mColumns)
{
    assert(nRows>0 && mColumns>0);

    r = nRows;
    c = mColumns;
    matrix = new double[r*c]{};

    //fills with zeros
    for(int i = 0; i<r*c; i++){
        matrix[i] = 0;
    }
}

Matrix::Matrix(int nRows)
{  
    assert(nRows>0);

    r = nRows;
    c = nRows;
    matrix = new double[r*c]{};
    for(int i = 0; i<r*c; i++){
        matrix[i] = 0;
    }
    //Makes the identity matrix
    for(int i = 0; i<r; i++){
        set(i,i, 1);
    }
}

Matrix::Matrix(const Matrix& other){
    r = other.getRows();
    c = other.getColumns();
    matrix = new double[r*c];
    *matrix = *other.matrix;
}



int Matrix::getIndex(int row, int col) const
{
    int index = row*c;
    index += col;
    return index;
}

int Matrix::getRows() const
{
    return r;
}
int Matrix::getColumns() const
{
    return c;
}

void Matrix::set(int row, int col, double value){
    matrix[getIndex(row, col)] = value;
}

double Matrix::get(int row, int col) const{
    return matrix[getIndex(row,col)];
} 

Matrix::~Matrix()
{

}

ostream& operator<<(ostream& os, const Matrix& m){
    for(int i = 0; i<m.getRows(); i++){
        for(int j = 0; j<m.getColumns(); j++){
            os << m.get(i,j);
            os << ' ';
        }
        os << '\n';
    }
    os << endl;
    return os;
}

Matrix& Matrix::operator=(Matrix rhs){
    r = rhs.r;
    c = rhs.c;
    swap(matrix, rhs.matrix);
    return *this;
}
C++ 指针 复制构造函数

评论

1赞 Drew Dormann 3/15/2023
*matrix = *other.matrix;这不是复制 C 样式数组的方法。您将更容易使用原始指针和 C 样式数组。std::vector
0赞 PaulMcKenzie 3/15/2023
为什么你的析构函数被注释掉了?你这样做搞砸了。底线是这样的——如果你有一个必须管理资源的类,并且你需要提供一个用户定义的复制构造函数、赋值运算符和析构函数,你必须全力以赴并编写所需的所有函数——你不能存根函数并拥有一个可以测试的程序。Matrixoperator=
0赞 463035818_is_not_an_ai 3/15/2023
该成员可以是 .如果你不想使用 ,你仍然应该编写一个只管理一维动态数组的类,因为这对于一个类来说已经绰绰有余了matrixstd::vectorstd::vector
0赞 PaulMcKenzie 3/15/2023
Matrix::~Matrix() { }-- 确切地说,您要求析构函数正常工作并调用数据。由于您在赋值运算符中使用并按值传递,因此在赋值运算符中工作的所有内容都基于要正确编码的复制构造函数析构函数。否则,您的程序会损坏。operator=Matrixdelete[]swapMatrix

答:

0赞 PaulMcKenzie 3/15/2023 #1

这不会将数据从一个数组复制到另一个数组:

*matrix = *other.matrix;

需要一个循环来复制数据,或者使用:memcpystd::copy

std::copy(other.matrix, other.matrix + r*c, matrix);

2赞 Vlad from Moscow 3/15/2023 #2

copy 构造函数中的此语句

*matrix = *other.matrix;

相当于

matrix[0] = other.matrix[0];

也就是说,它只设置新创建的数组的一个元素,但您需要复制所有元素。

例如,您可以使用 for 循环

for ( int i = 0; i < r * c; i++ )
{
    matrix[i] = pther.matrix[i];
}

或者,您可以使用标头中声明的标准算法std::copy<algorithm>

#include <algorithm>

//...

std::copy( other.matrix, other.matrix + r * c, matrix );

由于您使用的是基本类型 double,因此您还可以使用标头中声明的标准 C 函数,例如memcpy<cstring>

#include <cstring>

//...

std::memcpy( matrix, other.matrix, r * c * sizeof( double ) );

此外,析构函数应释放分配的内存

Matrix::~Matrix()
{
    delete [] matrix;
}

否则,复制赋值运算符定义如下

Matrix& Matrix::operator=(Matrix rhs){
    r = rhs.r;
    c = rhs.c;
    swap(matrix, rhs.matrix);
    return *this;
}

将产生内存泄漏。

在这个构造函数中

Matrix::Matrix(int nRows, int mColumns)
{
    assert(nRows>0 && mColumns>0);

    r = nRows;
    c = mColumns;
    matrix = new double[r*c]{};

    //fills with zeros
    for(int i = 0; i<r*c; i++){
        matrix[i] = 0;
    }
}

this for 循环

    //fills with zeros
    for(int i = 0; i<r*c; i++){
        matrix[i] = 0;
    }

是多余的。在此语句中,已分配数组的元素已设置为零

    matrix = new double[r*c]{};