Summary of the usage of const in C++

  • 2020-05-10 18:32:04
  • OfStack

const is widely used in C++, and different positions have different meanings. Therefore, I would like to write an article to make a summary of it.

First of all, make it clear that const is the basic meaning of "unchanged," but constant doesn't mean nothing remains the same, as we'll see below.

1. const and variables

Basic principle: the const variable (object) cannot be modified

The introduction of const into variables has to do with magic Numbers, which are the sudden appearance of a constant value (also known as a literal constant).


for(int i = 0; i < 512; i++)
{
// todo
}

In the above example, 512 is the magic number, and 512 suddenly appears in the loop, which makes it impossible to know its meaning, so const is introduced.


const int length = 512;
for(int i = 0; i < length; i++)
{
// todo
}

So we know that the loop is in the range of length.

1.1 const modifies a variable (or object) to make it a constant, which means that the value of the variable cannot be modified. Because of this, it must be initialized when defining a constant.

1.2 scope of const constant:

We know that declaring a variable in the global scope (specifically, a variable that is not const modified) applies to the entire program and can be referenced in other files, because declaring a variable in the global scope defaults to extern modified.

Declare an const variable in the global scope. The default is not an extern modifier, so it can only be used in this file. If you want to access it in other files, declare it explicitly as extern

2. const and references

Basic principle: an const reference is a reference to an const variable (object)


const int ival = 1024;
const int &refVal = ival;

2.1 the const reference can refer to the const variable of a related type (not this type)


double dval = 3.14;
const int &refVal = dval;

The compiler converts double to a temporary int object, and then binds the const reference to this temporary object, so changing the value of dval does not change refVal, which means that dval is still a non-const variable and refVal is still a constant reference.

The fourth version of primer is the above statement, but in VS2012, const can also point to a non-const variable of this type, and the reason for looking up information is probably to satisfy the reference-campatible condition.

In theory, we should strictly observe that constant references refer to constant objects, and extraordinary references refer to extraordinary objects to avoid errors.

3. const with Pointers

The relationship between const and pointer is divided into two types: the pointer modified by const and the pointer pointing to const object. The position of const is different from that of const

3.1 pointer to const object (const before pointer symbol *)

For an const object, you must point to it with a pointer to const. The reason for this is that the const modifier makes it impossible to change an object, whereas a pointer that does not point to const can be used to modify the object, which is not allowed.


const int ival = 1;
const int *ptrVal = &ival;

Conversely, for a pointer to an const object, you can point to any object. Let's first look at the pointer assignment process:


int *ptr = &val;

Assign the address of val to ptr, and since it is only the address that is assigned, it is not known whether the object that ptr is pointing to is const.

If we assign an address to a pointer to const, then the pointer considers it an const object, that is, the ptr pointer points to an object that "thinks" it is const.


int ival = 1;
const int *ptrVal = &ival;

The above procedure is correct, we need to make it clear that ival is not const variable, so we can change the value of ival by assigning ival a value. ptrVal points to an object that we think is const, so we cannot change the value of ival by *ptrVal.

3.2 pointer modified by const (const after pointer symbol *)


int *const ptr;

The above formula declares a pointer of type const, which means that the pointer itself is a constant and cannot be modified.

How to understand? The value of the pointer itself is 1 address, if the pointer itself is 1 constant, then the address value cannot be modified, that is, the pointer can only point to this address, can not point to other places. But the contents of the address to which the pointer points do not belong to the value of the pointer itself, so what it points to can be changed.


int ival = 1;
int *const ptr = &ival;
*ptr = 2;          // ok
int ivalTwo = 11;
ptr = &ivalTwo       // error

In summary, you can define an const pointer to an const object


const int *const ptr = &ival;

3.3 the error-prone const pointer in typedef


const int length = 512;
for(int i = 0; i < length; i++)
{
// todo
}
0

const string *s_prt; Thus, s_ptr is considered to be a pointer to const string.
First of all, ptr is 1 pointer, const is 1 pointer, so it should be string *const s_ptr; s_ptr is an const pointer to string.

4. const with arrays

The point of const with arrays is the principle that const must be initialized when defined, so when using dynamically allocated arrays, if the array stores objects of type const, it must be initialized (using the initialization symbol ()).

5. const and function return value

Modifies the return value of a function to return 1 constant.


const int length = 512;
for(int i = 0; i < length; i++)
{
// todo
}
1

5.1 returns are passed by value

If a function returns with a value passed in, say, an int type, then the function copies the returned value (say 47) to an external temporary storage location (producing a temporary copy), so adding const makes no sense


const int length = 512;
for(int i = 0; i < length; i++)
{
// todo
}
2

Two is exactly the same. It is important to note that value passing produces a temporary copy, which is inefficient (const is related to function arguments below), so it is usually returned by reference passing.

5.2 return passed by reference (rare)

If the return value is not an internal type, you usually use reference-passing to return the result, since the reference passes itself and does not need to produce a temporary copy. However, it is important to note that at this point only the 1 individual name is returned.


ClassType &foo();
const ClassType &foo();

Returns a reference value modified by const to indicate that the result of a function call can only be assigned to one const reference of the same type.

5.3 returns are passed by pointer


const int length = 512;
for(int i = 0; i < length; i++)
{
// todo
}
4

Means that the function returns a pointer of type ClassType, which points to an const object. The contents of the pointer cannot be modified, so the return value of the function can only be assigned to a pointer of type const.


const int length = 512;
for(int i = 0; i < length; i++)
{
// todo
}
5

6. const and function parameters

First of all, it should be clear that the purpose of const modification is to protect the modified content from being changed.
In C++, function parameters are divided into value passing, pointer passing and reference passing.

6.1 value transfer

Value passing generates a temporary copy when the function is called. Changes and operations on the incoming parameters in the function are operations on the copy and do not change the value of the argument itself, so const is not needed to protect it.
Value pass-through is well protected, but value pass-through has some disadvantages, such as the need to produce a temporary copy, and if the object is passed in, it needs to be constructed, copied, and destructed, which is not very efficient. Consider passing by reference at this point


const int length = 512;
for(int i = 0; i < length; i++)
{
// todo
}
6

The following kind of protection is meaningless:


const int length = 512;
for(int i = 0; i < length; i++)
{
// todo
}
7

6.2 reference passing

Reduce overhead by passing in a reference to an argument. Since the reference is itself, there is no need to generate a temporary copy.


void foo1(int &x);
void foo2(ClassType &ref);

For the above two functions, the form of function call and value passing is exactly the same, except that the x and ref obtained internally by the function are the references of the incoming arguments of the call. Because of this, references can change arguments by changing the parameters passed in by the function. This is dangerous for arguments, where the incoming reference needs to be protected from modification by an const modification.


const int length = 512;
for(int i = 0; i < length; i++)
{
// todo
}
9

In general, for basic internal types, there are no operations such as object construction, so the following two ways of protecting parameters from modification are basically effective.


void foo1(int x);
void foo1(const int &x);

6.3 pointer passing

Pointer passing is the same as reference passing in protecting parameters from being modified. Pointer passing also has a function to expand the range of received parameters:


void foo1(const ClassType *ptr);

Combining const with the pointer above, we know that ptr points to an object of type const, so! The object passed in is not necessarily an const modified object. It can be an const object or a non-const object. Conversely, if there are no formal parameters for the const modifier, only non-const objects can be passed in.

It should be clear that no matter whether the const object is passed in or not, this object cannot be modified by pointer, which is due to the relationship between const and the pointer above.

Finally, you need to know that const can only modify one input parameter. If it is an output parameter, neither reference passing nor pointer passing can be modified with const

7. Data members of const and class

Data members modified by const cannot be initialized in the constructor, but can only be initialized using the member initialization list.
It is my understanding that because data members are initialized using the member initializer list before the constructor is executed, initializing data members in the constructor is equivalent to assigning const twice, which is not allowed.

The reason for this understanding is that we can refer to the initialization of the reference type in the class, which must also be initialized in the initialization list, because the reference type must also be initialized at the time of definition, which requires the same as const1, so both of them can only use the member initialization list for initialization.

8. const and class member functions

In the const member function, const is located after the parameter list of the function (the function declaration indicates that the return value of the function is 1 constant).

The member function modified by const means that the member function is a read-only function and does not change the member variable.
The real meaning of const member function is that const actually modifies the implied parameter this pointer of the member function const, that is to say, const ClassType *this is passed in, because this points to an const object, so it cannot be modified.

Since this is a pointer to an object, we need to combine const with pointer knowledge again:

(1) const modifies this to get const ClassType *this, this points to an object that "thinks" it is const (that is, itself), so any object (const or non-const) can call an const member function. Since the incoming pointer regards itself as an const object, it cannot be modified.
(2) for a const object, when the member function called, the default all incoming this pointer parameter, because this now refer to a const object (itself), so is equivalent to a member function is decorated const, member function is a const member function, so, on the other hand, const object can only call const member function, because the const modified member function, this const a pointer is not.
(3) in 8.2 basically, further, each member functions can call other member functions, each member function into this pointer, so a member function call each other must maintain the consistency of the this pointer, so const member functions can call const member function, because the two incoming this Pointers are const modification. For a non-const member function, it passes in a non-const modified this pointer, so it cannot be called.

To understand what const really means, 1 must maintain the awareness that the const pointer is passed in by the const member function, and the object call needs to see whether the object (itself, pointer, reference) is const.


Related articles: