Tuesday 8 October 2013

All about const correctness

const is a keyword that prevent object being mutated. We used this a lot in class mostly to prevent an object being mutated or for a class-member function to change the member variable. Using const whenever appropriate is a good practice for type safety. There are classes that only have operations for non-const but not for const. In other words, const int may be different from int. This const correctness also becomes crucial especially when we dealing with pointer and passing by reference. Again, this site has a nice discussion about const correctness: http://www.parashift.com/c++-faq/const-correctness.html

In class, I noticed a lot of people confused between const variable and const function. So, I wrote this short example to explain the concept:

class Vector2
{
     float _x, _y;
public:
     void setX( const float i_x )
    {
        i_x++; ====> This is an error! i_x is a const that means we can't change it
        _x = i_x;
    }

    void setY( float i_y )
    {
        i_y++; ====> This is OK because i_y is not a constant value - you can change it however you want.
        _y = i_y;
    }

    float getX( ) const
    {
        _x++; ====> This is an error! The const after member function means we promise to the compiler that we are not going to change the value of the member class (which in this context is _x and _y). You can also say by putting the const keyword in the end of the function, we made this function a "read only" function.
        return _x;
    }
    float getY( )
    {
        _y++; ====> This is OK because we never promise to compiler not to make any changes to the member class.
        return _y;
    }
}

While this might not be the best example but I really hope this will help clarify their confusion. (At least three students told me it did =D ) While the const in getter function made the function read only, it also gives an access for the const Vector3. For example,
const Vector2 a;
a.getX(); ====> This is OK! The getX function is a const, which means we promise the compiler that we are not going to change the data member. And because this function is safe, compiler won't complain about it.
a.getY(); ====> This is an error! The getY function is not a const, compiler see this function is not safe as there is no promise not to change the data member.

I also noticed there are confusion about const object and const pointer as well. In short:
int *ptr; (read: *ptr is an int value)
*ptr = 0; ====> OK
ptr = NULL ====> OK

int const *ptrToConst; (read: *ptrToConst is a constant integer)
(= const int* ptrToConst)
*ptrToConst = 0; ====> This is an error! *ptrToConst is const
ptrToConst = NULL; ====> Ok

int* const constPtr; (read: constPtr is a constant integer pointer)
*constPtr = 0; ====> OK
constPtr = NULL; ====> This is an error! *constPtr is a constant integer pointer

int const * const constPtrToConst; (read: constPtrToConst is a constant pointer as is *constPtrToConst value)
(= const int* const constPtrToConst)
*constPtrToConst = 0; ====> This is an error!
constPtrToConst = NULL; ====> This is an error!

Phew! That's quiet a confusion. I hope this help the students and of course myself getting better with this const correctness. Btw, had I mention that I got this knowledge also from Wikipedia?

No comments:

Post a Comment