0

My goal was to implement my own Matrix class in C++. Firstly, I wanted to access an element using two consecutive subscript operator[]. However, when I tried to overload it, I came across an error of invalid initialization of non-const reference of type 'Matrix::Line&' from an rvalue of type 'Matriz::Line.

I've found out that only if I made it static then it'd work, but I can't explain what's going on with that static qualifier. Why did it work just that way but with wrong output?

class Matrix{
    int ** matrix;
    int lines, cols;
public:
    class Line{
        int *line;
        public: 
            Line(int* l):line(l){};
            Line(){};
            int& operator[](size_t i){
                return line[i];
            }
    };
    Matrix(int lin, int col):lines(lin), cols(col){
        matrix = new int*[lines];
        for(int i = 0; i < lines; i++){
            matrix[i] = new int[cols];
            for(int j = 0; j < cols; j++) matrix[i][j] = 0; // initialize 0s
        }
    }
    ~Matrix(){
        for(int i = 0; i < lines; i++) delete[] matrix[i];
        delete[] matrix;  
    }
    Line& operator[](size_t i){
        return Line(matrix[i]); // error!
        
        // static Line legit(matrix[i]); --> works
        // return legit;

    }
};

Plus, when I do:

int x = 4, y = 4;
Matrix M(x,y);
M[0][0] = 3;
for(int i = 0; i < x; i++){
    for(int j = 0; j < y; j++) cout << M[i][j] << " ";
    cout << "\n";
}
Output:
3 0 0 0 0
3 0 0 0 0
3 0 0 0 0
3 0 0 0 0

I can't see why it changes every row!

testing_22
  • 2,340
  • 1
  • 12
  • 28
  • 3
    The statement `return Line(matrix[i])` creates a temporary, which ceases to exist when the function returns, and returns a reference to it. That is not allowed, due to a rule disallowing creating a (non-`const`) reference to a temporary (since the reference would be unusable, as it refers to a non-existent object). Creating a `static` object means that an object is created that always exists in later code, so returning a reference to it is allowed. The output you get is because there is only one instance of a static - every usage of `M[i]` returns a reference to the SAME instance of `Line` – Peter May 30 '21 at 03:48
  • Just a tip. If you make a matrix, just allocate `with * height`. If you return coordinates (x,y), you use `y * width + x`. This way you data is bundled together which can drastically improve performance. – JMRC May 30 '21 at 03:49
  • This is a simple way to make a dynamic, 2D matrix with elements addressable by`[i][j]` https://stackoverflow.com/questions/36123452/statically-declared-2-d-array-c-as-data-member-of-a-class/36123944#36123944 – doug May 30 '21 at 05:03
  • You claim that the `static` keyword solved your problem. However, there are several changes between the code that compiles and the code that does not. What happens if you take the code that compiles and remove the `static` keyword? That is, still have a variable named `legit` that gets returned, but the declaration would be `/*static*/ Line legit(matrix[i]);`. *OK, it's undefined behavior, but it still compiles, right?* – JaMiT May 30 '21 at 05:31
  • I would go with `M(i,j)` instead of `M[i][j]`. And `M.row(i)` instead of `M[i]` – MatG May 30 '21 at 06:36

0 Answers0