Logo

Blog


C++ top-level qualifiers explained

In today's post, I would like to address the question, "What is a top-level cv-qualifier, and why is it important to understand?".

Well, the question isn't always phrased that clearly; I'm talking about the essence of the question.

What are cv-qualifiers

First of all, what does cv-qualifier mean? This stands for const and/or volatile qualifier. Both const and volatile are qualifiers to a datatype. Please note that I will ignore volatile for the most part; you can either exchange it with const or add it.

Let's have a look at an example:

1
2
3
4
5
char              robert{};   A 
const char        amy{};      B 
const char*       alfred{};   C 
char* const       linda{};    D 
const char* const melissa{};  E 

The issue with the cv-qualifiers is that they have a slightly different meaning once they are not used as top-level qualifiers. The lines B, D, and E have each a top-level qualifier const.

Distinguishing the multiple places of const

One rough view to distinguish the two different meanings of qualifiers is that as a top-level qualifier, we, as developers, tell the compiler to treat a variable as read-only. If the cv-qualifier appears as part of the type, it means that behind it are read-only data. Rewriting the former lines with these terms would lead to the following code:

1
2
3
4
5
char                                       robert{};   A 
const_by_user_request char                 amy{};      B 
read_only_data char*                       alfred{};   C 
char* const_by_user_request                linda{};    D 
read_only_data char* const_by_user_request melissa{};  E 

When I said const has a slightly different meaning, I was specifically talking about E. Here, in the legal C++ code, const appears twice but has different meanings. The first const says this pointer points to constant data, like a C-string literal. Something that resides in a read-only (ROM) section of your controller or might be a read-only page protected against writing by your operating system's kernel. In either case, modifying the data melissa points to is impossible.

The second const, const_by_user_request in the pseudo-code, is a request from us users to treat the pointer const, such that ++melissa or --melissa is illegal or that a user cannot assign a new value to amy (B). This is something the compiler can ignore in certain situations. What do I mean by that?

Applying the knowledge

In the example below in F, I can assign the const_by_user_request variable B to a plain char. The top-level cv-qualifier const (const_by_user_request) isn't important for the assignment. You still cannot modify amy and deliberately (at least hopefully) did not ask for lisa to be const as well. If the const would be important for the assignment, then a strong type-system would not allow the operation in F.

1
2
char lisa  = amy;     F 
char* fred = alfred;  G 

On the other hand, assigning the read_only_data alfred to fred in G leads to a compilation error because this operation would make the data behind alfred writeable. In this case, fred doesn't get a deep copy of alfred, instead fred would be just another way to access the data behind alfred.

1
error: assigning to 'char *' from 'const char *' discards qualifiers

More to come

These are the definitions. In my next post, I'll explain situations where this knowledge is vital.

Andreas