Understanding All the Details of C++ Const | by Debby Nirwan | Feb, 2022

It is vitally vital to grasp the main points of const qualifiers to assist enhance the standard of your code and the effectivity of your coding

Photograph by Zany Jadraque on Unsplash

The C++ const qualifier is without doubt one of the first stuff you study C++. You often begin by understanding that we must always use const for constants. That could be true, however truly we must always consider it as a option to inform compilers and different programmers our intentions about our code.

Once we add const to a variable (there are different use instances mentioned later), we are literally saying that we would like this variable to be read-only or immutable. Any try to switch it ought to be stopped by a compile error.

Within the next sections, I’ll cowl completely different situations the place we will use the const qualifier in our C++ code and what truly occurs below the hood.

const variables

The very first thing that involves thoughts, the simplest instance is const variables. This might be native variables in a operate, member variables in a category, or world variables.

The aim of including a const qualifier is to explicitly say that our intent is for the variable to be read-only. For instance, check out the operate beneath:

This operate signifies that the writer needs the val parameter and the native variable two to be read-only. Nothing particular occurs right here. Each variables are saved on stack reminiscence similar to non-const variables. The one distinction is, once we attempt to change the worth, we’ll get a compile error. The next code exhibits an try to switch val.

error: project of read-only parameter ‘val’

The identical goes for const member variables in lessons, the one distinction with non-const member variables is that once we attempt to modify them we’ll get the identical compile error proven above.

For world variables, there’s one other distinction, once we add a const qualifier to the variable, the variable will probably be saved within the read-only part of reminiscence as a substitute of the info part. The remaining is similar.

So it’s clear that the const key phrase is a means for us to speak our intentions to compilers and different programmers to say that we don’t need variables to alter at runtime.

Capabilities returning const

I discover that that is uncommon, however potential. We are able to add a const qualifier to the return kind of a operate. This solely is sensible once we return a user-defined kind, not a primitive kind like an int. Check out the instance beneath:

Discover that CreateT() returns a short lived variable that can be utilized to name SetVal(). Altering the return worth to be const can forestall this from occurring.

error: passing ‘const T’ as ‘this’ argument discards qualifiers [-fpermissive]

The compiler throws this error as a result of we try to cross a pointer to a const object to SetVal() which solely accepts non-const. In case you didn’t know or forgot, calling a member operate means implicitly passing a pointer (this pointer) to the operate. On this case,

int SetVal(T* this, const int val);

Passing const T* to this operate causes a compile error as a result of we try to implicitly take away the const qualifier.

Nevertheless, there’s a draw back of returning a const object, it prevents transfer semantics which was launched from C++11. Now, let’s assume that our class T allocates reminiscence dynamically to handle a few of its member variables. After all, we need to use transfer semantics to keep away from the costly copying course of.

If CreateT() returns a const object, line 3 within the code above will probably be invoking copy project operator, whereas if it returns a non-const object it will likely be invoking transfer project operator. It is because the compiler will select the copy project operator overload which accepts a const object reference.

So until you’re utilizing an older model of C++ there’s no motive to return a const object. It might be good observe for the calling facet to not name a operate that tries to switch a short lived object.

const (member) features

One other use of const qualifier is for member features of a category. The syntax is exclusive or awkward as a result of it’s positioned on the finish of a operate declaration.

It ought to be written that means as a result of the variable that it qualifies is hidden. Recall that each one non-static member features have a hidden pointer to themselves known as this. The const qualifier we’re discussing right here is for qualifying that pointer.

Going again to our instance above, the T class has a member operate known as SetVal().

int SetVal(const int val);

If you compile the code, the compiler modifies it to:

int SetVal(T* this, const int val);

To make the primary variable const, we have to write our code as:

int SetVal(const int val) const;

So, the compiler modifies it to:

int SetVal(const T* this, const int val);

For now, ignore the truth that SetVal() doesn’t make sense to be const since we need to modify the thing. The purpose I’m making an attempt to make right here is the const qualifier that exists to make this pointer factors to a const object.

Any try to alter any member variable in that operate will trigger a compile error. One other vital level is the one which we mentioned above, whenever you declare a const object of kind T, you’ll be able to solely name const features. That’s as a result of you’ll be able to’t convert a pointer to a const object to a pointer to a non-const object as a result of it will violate constness.

Changing const to non-const and vice versa

There’s something that I discover complicated particularly for newcomers. That’s, passing a parameter by reference or pointer and returning a reference or pointer from a operate.

The complicated half is the distinction within the const qualifier. Let’s have a look at some examples.

Once we name Course of(enter); in line 10 we make a replica of the enter object, there isn’t a downside altering from non-const to const Enter model as there are two copies. One other means can also be right:

The identical goes for the return worth, wherever we add the const qualifier it is going to work as a result of we make a replica.

Once we take care of references, it’s completely different. Once we change our operate to simply accept const reference the conduct stays the identical, we will cross const and non-const objects to it.

Each variations beneath work.

However once we change our operate to simply accept the non-const reference proven beneath, we will solely cross non-const objects to it.

It is because not like passing by worth, once we use a reference, we don’t make a replica, we use the identical object. Subsequently we can not change the qualifier of an object from const to non-const.

The next instance is fascinating.

On this instance, we cross the const reference on line 9 to a operate that accepts an object by worth. On this case, it really works, regardless that we modified from const to non-const.

It’s complicated due to the magic the compiler does. References are simply pointers below the hood. The compiler does all of the work to do the conversion for us. What occurs, on this case, is the next:

The compiler modifies our code to pass-by-value, so on this case, we make a replica of it. That’s why it really works. Simply to finish the instance, within the earlier model above that is what occurs after the compiler modifies our code:

All of it turns into clearer once we see the pointer model.

Including/Eradicating const qualifier with const_cast

Within the part above we’ve got seen that we will have a const pointer or a const reference that factors to a non-const object, the opposite means round isn’t potential.

Now, when you’ve got situations the place you’ll want to modify the constness, both means, you need to use const_cast. The next are some examples.

On this instance, the library code permits us to switch worth for some motive. However, we determined that we don’t need to do it. On this case, we will add a const qualifier to it by utilizing const_cast.

The opposite means can also be potential, however not advisable.

This code works, as a result of the unique variable, worth at line 7, is a non-const object. So we will take away the const qualifier and modify the worth. However, if the unique variable is const as proven within the code beneath, the result’s undefined.

This code compiles with out error, however the result’s undefined. This instance will print the next (examined with GCC and clang):

mutableValue: 100
worth after callback: 10

Please observe that, if we write our code proper, we must always by no means use const_cast. The one use case is probably once we take care of library code that provides us a pointer to a non-const object and we need to make it safer by modifying it to a pointer to a const object.

  • The const qualifier is essential to precise our intention to compilers and different programmers that we would like the thing to be read-only
  • The compiler helps us carry out checks by throwing errors when there are makes an attempt to alter our read-only variables
  • A const qualifier on a member operate is simply syntax for including a const qualifier to this pointer
  • We are able to return a const worth from a operate to forestall momentary object modification, however doing so has the unintended impression of stopping transfer semantics
  • We are able to modify constness of an object utilizing const_cast, however legitimate use instances are very uncommon, for instance when coping with third social gathering legacy libraries you could’t modify

More Posts