C++ - pointer this

Asked

Viewed 51 times

0

The Rotatex(float) and Scale(float, float, float) functions of the mat4 class return the this pointer. The purpose was to create a temporary instance of mat4 to store the pre-multiplication between the Scale and Rotate functions. As follows:

mat4 mat4::RotateX(float theta){
    matrix[1][1] = cos(DegToRad(theta));
    matrix[2][1] = sin(DegToRad(theta));
    matrix[1][2] = -sin(DegToRad(theta));
    matrix[2][2] = cos(DegToRad(theta));
    return *this;
}
mat4 mat4::Scale(float x, float y, float z){
    matrix[0][0] = x;
    matrix[1][1] = y;
    matrix[2][2] = z;
    return *this;
}
    mat4 transform;
    mat4 temp;
       
    transform = temp.RotateX(theta) * temp.Scale(x, y, z); 

You have the following attribute of the class:

float matrix[4][4]

The mat4 class has a multiplication operator overload (*) which performs a matrix multiplication operation.

mat4 mat4::operator*(const mat4& m) const{
    mat4 mult;
    for(uint8_t i = 0; i < 4; i++){
        for(uint8_t j = 0; j < 4; j++){
            mult[i][j] = matrix[i][0] * m[0][j] 
                       + matrix[i][1] * m[1][j] 
                       + matrix[i][2] * m[2][j] 
                       + matrix[i][3] * m[3][j];
        }
    }
    return mult;
}

Thus, temp is the result of concatenation between a scale operation and rotation.

As it stands, this structure makes it possible to do this:

transform.Scale(x, y, z);

Is this legal for the language considering that Scale() returns the this pointer, which in turn stores the address of the instance that calls the function? That would be the same as copying objects?

2 answers

0

Yes, if you want to return the object itself you change the prototype to return a reference.

Exchanging:

 mat4 mat4::Scale(float x, float y, float z)

for:

 mat4& mat4::Scale(float x, float y, float z)

0


Thus, temp is the result of concatenation between a scale operation and rotation.

This seems very confusing and is creating an unnecessary copy because what you are returning in each of these methods is not a pointer, but an object mat4. To avoid the copy you must return by reference (just change the return type of mat4 for mat4&.

But even if you switch to reference and the code does what you want, I still don’t think it’s a good case.

Seeing a method called RotateX and another call Scale What comes to mind as the natural is that they modify the current object, but in your case they are working more as initiators of a new object (they use nothing of the current state of the object). I think, considering what these two methods currently do, they could be modified to be "static factory methods". That is, static methods that you use to create a new object. With that the line

transform = temp.RotateX(theta) * temp.Scale(x, y, z);

viraria

transform = mat4::RotateX(theta) * mat4::Scale(x, y, z);

Also, names can be more suggestive. Something like exchanging RotateX, which gives the impression that it will rotate the current matrix in some way, to something like fromRotationX and Scale for something like fromDiagonal (since what you’re doing is creating a diagonal matrix and has nothing to do with scaling an array). So the line initiating transform would be

transform = mat4::fromRotationX(theta) * mat4::fromDiagonal(x, y, z);

The fact that you are using static methods in the above line makes it clear that you are creating two new objects that will be multiplied to get transform and the names make it clearer how these objects are created. Since they are now static methods, then the return type is just mat4. An implementation to fromDiagonal could be like below

// Coloque static no .h
static mat4 mat4::fromDiagonal(float x, float y, float z){
    mat4 result;
    result.matrix[0][0] = x;
    result.matrix[1][1] = y;
    result.matrix[2][2] = z;
    return result;
}

An interesting detail is that the compiler is intelligent and even returning a mat4 it can avoid copying in the most common cases when you use this static method. If you do something like

mat4 umaMatrizDiagonal = mat4::fromDiagonal(x, y, z);

compiler will see the return value of fromDiagonal is assigned to a variable and when it creates result inside fromDiagonal he already creates in the place where umaMatrizDiagonal is thus avoiding the copy.

  • A small observation for fromDiagonal function, in mat4.Matrix the correct one should be result.Matrix?

  • Yes, you’re right. Corrected.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.