Thomas Paine
Thomas Paine

Reputation: 313

Am I misunderstanding how pointers work?

I have a class Matrix and another class Camera that I want to utilize the Matrix in. My Matrix class looks like this:

class Matrix4f {
    public:
        Matrix4f() {
            this->setMatrix(EMPTY);
        }

        Matrix4f(Matrix4f &m2) {
            this->setMatrix(m2.matrix);
        }

        static Matrix4f& Matrix4f::identity() {
           Matrix4f& identity = Matrix4f() ;
           identity.setMatrix(IDENTITY);
           return identity;
        }

        void setMatrix(float f[4][4]) {
            for (int r = 0; r < 4; r++) {
                 for (int c = 0; c < 4; c++) {
                      this->matrix[r][c] = f[r][c];
                 }
            }
        }

        Matrix4f& operator=(const Matrix4f &m2) {
             this->setMatrix(m2.matrix);
        }
    private:
        float matrix[4][4];
        static float EMPTY[4][4] = {
             { 0, 0, 0, 0 },
             { 0, 0, 0, 0 },
             { 0, 0, 0, 0 },
             { 0, 0, 0, 0 }
        }; // initialize an empty array (all zeros);
        static float IDENTIY[4][4] = {
             { 1, 0, 0, 0 },
             { 0, 1, 0, 0 },
             { 0, 0, 1, 0 },
             { 0, 0, 0, 1 }
        }; // initialize a identity (array)
}

And I have this in my camera class:

class Camera {
    public:
        Camera() {
            this->calculateProjection();
        }

        Matrix4f* getProjection() {
            return this->projection;
        }
    private:
        Matrix4f* projection;

        Matrix4f* calculateProjection() {
             this->projection = &Matrix4f::identity();
             // modify this->projection...

             return this->projection;
        }
  }

When I try to create a Camera instance and then get its projection I get something that looks like a corrupted object (the matrix is filled entirely to large negative numbers).

I am really confused what is causing my code to misbehave like this.
I am fairly certain it deals with a reference being automatically deleted by the compiler, and I think it deals with the identity matrix but it doesn't really make sense.

Shouldn't the identity matrix be copied into the projection matrix, so it wouldn't even matter if the identity matrix gets garbage collected?

I found that I can actually make this code work by either making the identity matrix create a new Matrix4f() and returning that OR making getProjection() return the calculateProjection().
Problem is, I really don't want to do either of those.
I don't want Identity to construct a new Matrix4f because then I have to deal with destroying it, and I don't want getProjection() to call calculateProjection() because that method is expensive,
and should really only be called once as the Projection matrix never changes.

Upvotes: 0

Views: 124

Answers (2)

AndersK
AndersK

Reputation: 36092

Your

 Matrix4f& Matrix4f::identity() {
           Matrix4f& identity = Matrix4f() ;
           identity.setMatrix(IDENTITY);
           return identity;
        }

returns a reference to a local object. Once identity() exits the object is gone.

You need to allocate it on the heap then return that.

Alternatively declare a matrix in you class Camera

  ...
  private:
    Matrix4f projection;

    Matrix4f& calculateProjection() { 
         ... modify ...
         return this->projection;
    }
   ...

Upvotes: 2

Am I misunderstanding how pointers work?

Maybe. Your code has several problems that I can see:

    Matrix4f& Matrix4f::identity() {
       Matrix4f& identity = Matrix4f() ;
       identity.setMatrix(IDENTITY);
       return identity;
    }

This creates a temporary object, and a reference to it (the reference is called identity). I'm not sure whether the temporary object is destroyed after Matrix4f& identity = Matrix4f() ;, or when the function returns - but either way, the temporary object is destroyed before the function returns and so the function returns a reference to an object that has been destroyed.

this->projection = &Matrix4f::identity();

this->projection is then set to the address of the temporary object that was destroyed.

Later on, you try to access the temporary object that was destroyed, and unsurprisingly get garbage data.

Also, identity (the function) isn't static, so you can't call it as Matrix4f::identity().

Upvotes: 1

Related Questions