DEV Community

Coral Kashri
Coral Kashri

Posted on • Originally published at cppsenioreas.wordpress.com on

LConst PConst - C++

The const keyword is widely used within almost every C++ program. It symbolizes the idea of a constant variable, object, function, and more, and is meant to forbid us from manipulating and changing the content of a memory location within a certain scope. However, as we learned before “There is nothing more deceptive than an obvious fact.” (Sherlock Holmes).

Const Rules

In this article, I won’t dive deeply into the const rules, but just move briefly on const ideas I consider as crucial for the point I want to talk about.

Let’s start with the basic rules of const. The most basic const example is a constant variable:


const int a = 42;

Enter fullscreen mode Exit fullscreen mode

In this example, we initialize a constant integer with a value of 42. Any const variable should be initialized at the creation stage (due to the inability to initialize it later). Once the variable is initialized, there is no way to change it (Well… const_cast but it didn’t get into this article scope).

Const location

const keyword can be written in multiple locations of the type:


const int a = 5;
int const b = 6;

Enter fullscreen mode Exit fullscreen mode

The result is the same, in both cases the variables are constant. However, this ability has a great impact when pointers join the picture.


int val;
const int* a = &val;

Enter fullscreen mode Exit fullscreen mode

In this example, we initialize a mutable (not const) int variable named “val”, and a “const” pointer to it called “a”. Now, I say “const” because it’s only a partial const pointer. here is actually applied only to the pointer’s value, not the pointer itself. which means that we can modify this pointer to point to another variable, but we won’t be able to modify the variable content through this pointer. For example:


int val;
const int* a = &val;

// *a = 5; // Won't compile. The integer content is protected by the const qualifier.

int val2;
a = &val2; // Works just fine.

Enter fullscreen mode Exit fullscreen mode

Now, this also means that we can create the pointer variable without assigning a value to it at the creation stage:


// const val; // doesn't compile
const int* a; // Works.

Enter fullscreen mode Exit fullscreen mode

If we want to protect the pointer, we have to change the const qualifier location. Let’s inspect the different possible locations for the const qualifier in this example:


const int* a; // the int content is being protected.
int const* b; // the int content is being protected.

int val;
int* const c = &val; // the pointer is being protected, and therefore have to be initializes at the creation stage.

Enter fullscreen mode Exit fullscreen mode

We can combine the different const locations as long as they don’t repeat the meaning in the same variable:


int val;
const int* const a = &val; // both the pointer and its content are protected.
int const* const b = &val; // both the pointer and its content are protected.
// const int const c; // Won't compile because the secound const qualifier have the same meaning of the first const qualifier.

Enter fullscreen mode Exit fullscreen mode

The rule is simple if a const is the first qualifier in the type, the const will be applied to the next element of it. Otherwise, it’ll always be applied to the previous component of it.

Side note: A constant pointer equivalent is a reference variable, for example:


int val;
int &a = val;
int *const b = &val;

Enter fullscreen mode Exit fullscreen mode

Variables “a” and “b” here have the same meaning, they are both protecting the pointer from changes.

Class Const Member Functions

Now that we know the rules for constant variables, let’s talk about constant functions.

Constant functions are defined as functions that can not modify a class’s variables. For example:


class A {
public:
    void func() const {
        // a = 5; // Won't compile
    }

private:
    int a;
};

Enter fullscreen mode Exit fullscreen mode

Everything seems great, right? Let’s inspect another case:


class A {
public:
    void func() const {
        // a = &val; // Won't compile
    }

private:
    int *a;
    int val;
};

Enter fullscreen mode Exit fullscreen mode

So far, everything seems just right. If a function is const, the class’s members can not be modified. It’s time to break this rule a little:


class A {
public:
    A() : a(&val) {}

    void func() const {
        *a = 42; // Wait, WHAT?!
    }

private:
    int *a;
    int val;
};

Enter fullscreen mode Exit fullscreen mode

I guess it’s the right time to go back to the quote “There is nothing more deceptive than an obvious fact.” of Sherlock. The constant function only protects the last element of the class’s members’ types. So in this example, we modified a member variable content through a pointer member inside a constant member function.

Marking this function as a const function is a mistake that might lead to bugs if someone will relay on this const qualifier. This function actually performs a hidden const_cast and it shouldn’t. In order to fix this issue, the right thing would be to remove the const qualifier from this function.

Code inspection tools sometimes might advise us to add a const qualifier to this function, because the compiler allows that, but we shouldn’t. Adding a const qualifier to a class’s function should always be done only after careful consideration of whether this function modifies the class’s state/variables or not.

Let’s see an even more confusing example:


class A {
public:
    A() : a(val) {}

    void func() const {
        a = 42; // Oh no...
    }

private:
    int &a;
    int val;
};

Enter fullscreen mode Exit fullscreen mode

This time we even don’t see the * when modifying the content. And it’s not even a UB! It’s totally legal by the language’s standard.

Conclusion

The title LConst PConst stands for Logical Const vs. Physical Const. We should always prefer to use the logical one over the physical one, and the compiler doesn’t help us this time.

I didn’t dive into more aspects of the const qualifier in this article, but I might do it in future articles. If you have a specific request, feel free to contact me on the dedicated channels of this blog like Discord and Telegram.

Feel free to leave your opinions in the comments section.

Top comments (0)