I've been having a hell of a time trying to solve this. What I am trying to do is use operator overloading so that my objects behave more like a multi dimensional array. I've found solutions to several of the smaller problems involved in making this happen but whenever I try to put it all together there is one issue or another, either lvalue assignment error or invalid initialization from rvalue or just straight up seg fault. I would appreciate any advice TY.
#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;
CodePudding user response:
In main()
, m
is a pointer to a Matrix
object, so you need to dereference the pointer in order to access the Matrix
object so you can invoke your Matrix::operator[]
on it, eg:
int main()
{
Matrix *m = new Matrix(5, 5);
(*m)[2][2] = "It Works";
std::cout << (*m)[2][2] << std::endl;
delete m;
return 0;
}
Otherwise, the pointer is not really needed in your example to begin with, eg:
int main()
{
Matrix m(5, 5);
m[2][2] = "It Works";
std::cout << m[2][2] << std::endl;
return 0;
}
Either way, your Proxy
does not need to implement operator=
at all, eg:
class Proxy {
std::string *mm;
public:
Proxy(std::string *s) : mm(s) {}
std::string& operator[](int index) {
return mm[index];
}
};
A statement like m[2][2] = "...";
will not invoke your Proxy::operator=
, it will invoke only Proxy::operator[]
. A statement like m[2] = "...";
would be needed to invoke Proxy::operator=
, which doesn't make sense to do in a multi-dimensional scenario.
Also, your Matrix
constructor has a bug - writing to m[x]
is going out of bounds of the m[]
array, so the array is not actually filled at all, and you are corrupting surrounding memory, and leaking memory. You need to write to m[i]
instead:
//m[x] = new std::string[y];
m[i] = new std::string[y];
After fixing that, Matrix
is still leaking memory, as it does not implement a destructor to free the std::string
s. You must delete[]
anything you new[]
(same with delete
and new
).
And then, you should finish off implementing support for the Rule of 3/5/0, by implementing a copy constructor and a copy assignment operator (your example code does not need them, but production code should always have them), eg:
#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;
}
However, rather than using new[]
manually, consider using std::vector
instead (which you are already aware of, since you have #include <vector>
in your code). This way, the Rule of 3/5/0 can be handled entirely by the compiler for you. std::vector
and std::string
are both fully compliant with the Rule, and so any compiler-generated destructor, copy constructor, and copy-assignment operator in Matrix
will suffice, eg:
#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]);
}
};