使用下标和等于运算符重载的赋值和检索

Assignment and retrieval using subscript and equals operator overloads

我一直在努力解决这个问题。我想要做的是使用运算符重载,以便我的对象表现得更像一个多维数组。我已经找到了解决实现这一目标所涉及的几个较小问题的解决方案,但每当我尝试将它们放在一起时,就会出现一个或另一个问题,要么是左值分配错误,要么是右值初始化无效,要么就是直接段错误。如果有任何建议,我将不胜感激。

#include <iostream>
#include <vector>
#include <string> 

class Matrix {
  std::string **m;
 public:
  Matrix(int x, int y) {
    m = new std::string*[x];
    for (int i = 0; i < x; i++)
      m[x] = new std::string[y];
  }
  class Proxy {
    std::string *mm;
    int lastIndex = 0;
  public:
    Proxy(std::string *s) : mm(s) {}
      std::string &operator[](int index) {
      lastIndex = index;
      return mm[index];
    }
    std::string &operator=(std::string s) {
      mm[lastIndex] = s;
      return mm[lastIndex];
    }
  };
  Proxy operator[](int index) {
    return Proxy(m[index]);
  }
};

int main()
{
  Matrix *m = new Matrix(5, 5);
  m[2][2] = std::string("It Works");
  std::cout << m[2][2] << std::endl;
  return 0;

main()中,m是指向Matrix对象的指针,所以你需要解引用指针才能访问Matrix 对象,这样您就可以在其上调用您的 Matrix::operator[],例如:

int main()
{
  Matrix *m = new Matrix(5, 5);
  (*m)[2][2] = "It Works";
  std::cout << (*m)[2][2] << std::endl;
  delete m;
  return 0;
}

Online Demo

否则,您的示例中并不真正需要指针,例如:

int main()
{
  Matrix m(5, 5);
  m[2][2] = "It Works";
  std::cout << m[2][2] << std::endl;
  return 0;
}

Online Demo

无论哪种方式,您的 Proxy 根本不需要实施 operator=,例如:

class Proxy {
  std::string *mm;
public:
  Proxy(std::string *s) : mm(s) {}

  std::string& operator[](int index) {
    return mm[index];
  }
};

m[2][2] = "..."; 这样的语句不会调用您的 Proxy::operator=,它只会调用 Proxy::operator[]。需要像 m[2] = "..."; 这样的语句来调用 Proxy::operator=,这在多维场景中没有意义。


此外,您的 Matrix 构造函数有一个错误 - 写入 m[x] 超出了 m[] 数组的范围,因此实际上根本没有填充数组,并且你正在破坏周围的内存, 泄漏内存。您需要改为写入 m[i]

//m[x] = new std::string[y];
m[i] = new std::string[y];

修复后,Matrix 仍然 内存泄漏,因为它没有实现释放 std::string 的析构函数。您必须 delete[] 任何您 new[] 的东西(与 deletenew 相同)。

然后,您应该通过实现复制构造函数和复制赋值运算符来完成对 Rule of 3/5/0 的实现支持(您的示例代码不需要它们,但生产代码应该始终有它们),例如:

#include <iostream>
#include <string> 
#include <utility>

class Matrix {
    std::string **m;
    int m_x, m_y;
public:
    Matrix(int x = 0, int y = 0) : m_x(x), m_y(y) {
        m = new std::string*[x];
        for (int i = 0; i < x; ++i)
            m[i] = new std::string[y];
    }

    Matrix(const Matrix &src) : m_x(src.m_x), m_y(src.m_y) {
        m = new std::string*[m_x];
        for (int i = 0; i < m_x; ++i) {
            m[i] = new std::string[m_y];
            for (int j = 0; j < m_y; ++j) {
                m[i][j] = src.m[i][j];
            }
        }
    }

    ~Matrix() {
        for (int i = 0; i < m_x; ++i)
            delete[] m[i];
        delete[] m;
    }

    Matrix& operator=(const Matrix &rhs) {
        if (&rhs != this) {
            Matrix temp(rhs);
            std::swap(m, temp.m);
            std::swap(m_x, temp.m_x);
            std::swap(m_y, temp.m_y);
        }
        return *this;
    }
    
    class Proxy {
        std::string *mm;
    public:
        Proxy(std::string *s) : mm(s) {}

        std::string& operator[](int index) {
            return mm[index];
        }
    };

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

int main()
{
    Matrix m(5, 5);
 
    m[2][2] = "It Works";
    std::cout << m[2][2] << std::endl;
 
    Matrix m2(m);
    std::cout << m2[2][2] << std::endl;
 
    Matrix m3;
    m3 = m2;
    std::cout << m3[2][2] << std::endl;

    return 0;
}

Online Demo

但是,与其手动使用 new[],不如考虑使用 std::vector(您已经知道,因为您的代码中有 #include <vector>)。这样,3/5/0 规则可以完全由编译器为您处理。 std::vectorstd::string 都完全符合规则,因此 Matrix 中的任何编译器生成的析构函数、复制构造函数和复制赋值运算符都足够,例如:

#include <iostream>
#include <vector>
#include <string> 

class Matrix {
    std::vector<std::vector<std::string>> m;
public:
    Matrix(int x = 0, int y = 0) {
        m.resize(x);
        for (int i = 0; i < x; ++i)
            m[i].resize(y);
    }

    class Proxy {
        std::vector<std::string> &mm;
    public:
        Proxy(std::vector<std::string> &s) : mm(s) {}

        std::string& operator[](int index) {
            return mm[index];
        }
    };

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

Online Demo