0

我有一个行为类似于矩阵的类。所以用例是这样的:

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++ 新手,所有这些东西真的很令人困惑,所以感谢任何有用的建议......

4

1 回答 1

1

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

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

比这更重要的是您正在泄漏内存。当您调用operator=一个对象时,您正在就地创建一个不同的对象Matrix,而无需事先释放它所持有的内存。那是内存泄漏。

的实现operator=也不是线程安全的。如果为任何内部数组分配内存失败并引发异常,则您的对象将处于既不是原始状态也不是有效状态的状态。这本身就是不好的。

与前一个相关,尽管更正一个可能会导致另一个,如果存在aliasingoperator= ,您的实现是不安全的,也就是说,如果您自行分配它会失败。第一行将泄漏内存并创建新缓冲区,然后从那里将新缓冲区复制到自身中,丢失原始信息。

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

通过调用const Matrix b = a;我想创建 Matrix 的新实例,它在那一刻将具有相同的 a 值。然而,b 受到改变 a 中的值的影响。

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

于 2013-04-02T01:21:30.400 回答