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

我花了很长时间试图解决这个问题。我想要做的是使用运算符重载,以便我的对象行为更像一个多维数组。我已经找到了几个小问题的解决方案,但每当我试图将所有问题放在一起时,都会出现这样或那样的问题,要么是左值赋值错误,要么是来自右值的无效初始化,或者只是直接的seg错误。如果您能给我提建议,我将不胜感激。

#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

相关文章