矩阵类的深层副本

时间:2013-04-02 01:07:36

标签: c++ pointers operator-overloading overloading

我有一个类似矩阵的类。 因此,用例类似于:

Matrix matrix(10,10);
matrix[0][0]=4;
//set the values for the rest of the matrix
cout<<matrix[1][2]<<endl;

代码:

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <sstream>

using namespace std;

class Matrix {
public:


    Matrix(int x, int y);

    class Proxy {
    public:

        Proxy(int* _array) : _array(_array) {
        }

        int &operator[](int index) const {
            return _array[index];
        }
    private:
        int* _array;
    };

   Proxy operator[](int index) const {
      return Proxy(_arrayofarrays[index]);
   }
   Proxy operator[](int index) {
      return Proxy(_arrayofarrays[index]);
   }

    const Matrix& operator=(const Matrix& othersales);

private:
    int** _arrayofarrays;
    int x, y;
};

Matrix::Matrix(int x, int y) {
    _arrayofarrays = new int*[x];
    for (int i = 0; i < x; ++i)
        _arrayofarrays[i] = new int[y];
}

const Matrix& Matrix::operator=(const Matrix& othermatrix) {
    new (this) Matrix(x, y);
    for (int i = 0; i < 3; i++)
        for (int j = 0; j < 3; j++)
            _arrayofarrays[i][j] = othermatrix._arrayofarrays[i][j];

    return *this;
}

int main() {

    Matrix a(2, 3);
    a[0][0] = 1;
    a[0][1] = 2;
    a[0][2] = 3;
    a[1][0] = 4;
    a[1][1] = 5;
    a[1][2] = 6;

    cout << a[1][2] << endl;
    //prints out 6


    const Matrix b = a;
    cout << b[1][2] << endl;

    a[1][2] = 3;

    cout << a[1][2] << endl;
    // prints out 3
    cout << b[1][2] << endl;
    // prints out 3 as well
}

通过调用const Matrix b = a;我想要创建新的Matrix实例,其中包含与a相同的值。但是,更改b中的值会影响a。因此,如果我更改了a中的某个值,那么它也会在b中更改。我不希望它表现得像这样。

所以我需要创建一个不受b本身影响的a副本。

那些可能是个愚蠢的问题,但对我来说,作为一个java家伙和C ++新手都是令人困惑的东西,所以感谢任何有用的建议......

1 个答案:

答案 0 :(得分:1)

您的实施存在一些问题。简单的就是你得到的错误......

Matrix类中,operator[]是非const成员函数,这意味着它只能在非const对象上执行。您的operator=会在const &之前截取右侧对象,因此您无法在其上调用operator[]。这里的问题是你没有提供operator[]的实现,它承诺不修改对象,一旦你将它添加到它应该编译的类型中。

比这更重要的是你正在泄漏记忆。当您在某个对象上调用operator=时,您正在创建一个不同的Matrix,而不会释放它所持有的内存。那是内存泄漏。

operator=的实现也不是线程安全的。如果为任何内部数组分配内存失败并抛出异常,则会使对象处于既不是原始状态也不是有效状态的状态。这本身就很糟糕。

与上一个相关,只要纠正一个可能导致另一个,如果存在别名,则operator=的实施是不安全的,也就是说,如果你失败了自己分配。第一行将泄漏内存并创建新缓冲区,然后从那里将新缓冲区复制到自身,丢失原始信息。

最后,如果您放弃使用operator[]的要求并使用两个索引代替operator(),则可以改进该类型的实现。用户代码必须进行调整(看起来不像二维数组),但它提供了更多的表示自由(您可以以任何您想要的方式在内部存储信息)。同时,不需要分配指针数组,然后分配int的N个数组。您可以执行NxM ints的单个内存分配,并执行指针算法来寻址每个位置(这与使用operator[] / operator()无关),这将减少内存占用和使布局更紧凑,提高缓存性能(更不用说将动态分配数量减少M倍)

  

通过调用const Matrix b = a;我想创建Matrix的新实例,那个时刻将具有相同的a值。然而,更改a中的值会影响b。

嗯,这是我在第一次阅读中遗漏的另一个问题。表达式const Matrix b = a;不涉及operator=,而是复制构造函数。谷歌的另一件事:三个规则(基本上,如果你手动实现复制构造函数,赋值或析构函数之一,你可能想要实现所有这三个)。在没有定义自己的复制构造函数的情况下,编译器将隐式地为您执行一个浅复制(即复制存储在Matrix中但不为其分配内存的指针)。复制完成后Matrix 共享相同的内存,如果析构函数释放内存,当第二个析构函数运行并尝试delete []时,您将遇到未定义的行为已经删除的记忆。