1. Constants
Use const
to define constant objects. Once defined, such objects cannot be modified while the program is running. Therefore, constant objects must be initialized.
const int i = 0; // constant i = 5; // cannot assign to variable 'i' with // const-qualified type 'const int' // Unable to assign value to variable 'i' with const qualified type
2. Constant expression
const emphasizes the immutability of objects at runtime, which means that you can define a const at runtime, while constexpr emphasizes that the result is determined at compile time. Const cannot be replaced at the compilation stage like constexpr, and the efficiency is not as good. Therefore, it is recommended to use constexpr
to define all existences that you identify as constant expressions.
Note that constants and variables are not relative concepts in C++. A constant is a variable that is modified with const so that its value cannot be changed.
To define a constant expression, you must first modify it with the const
operator, and then initialize it with another constant expression, which can be a literal or an operation expression of a literal.
int getsize(){<!-- --> return 20; } const int size = 20; // constant expression const int size_1 = size + 1; // constant expression const int size_2 = getsize(); // not a constant expression
2.1 constexpr keyword (C++11)
It can be seen that although the return value of the getsize
function is fixed at 20, size_2
still cannot be determined as a constant expression. This is because the compiler cannot determine getsize< Does the result of /code> meet the requirements? At this time, you can use
constexpr
instead of const
to define all symbols that you consider to be constant expressions.
constexpr int getsize(){<!-- --> return 20; } constexpr int size = 20; // constant expression constexpr int size_2 = getsize(); // constant expression
Three points to note:
- Only the return value of a function decorated with
constexpr
can be used to initialize otherconstexpr
. - When using
constexpr
to define a pointer, it only indicates that the pointer is a constant expression and has nothing to do with the object it points to. - For situations where
constexpr
is used but does not meet the requirements for constant expressions, a compile-time error will occur. For example:error: type name does not allow constexpr specifier to be specified
. *
2.2 The difference between const and const
The const object of a non-constant expression is a variable. It cannot be replaced at the compilation stage like constexpr, which is not as efficient. Therefore, it is recommended to use constexpr< for all expressions that you identify as constant expressions. /code> to define.
Write a program below and compile it to deepen your understanding.
constexpr int getsize(){<!-- --> return 20; } int getsize_2(){<!-- --> return 20; } constexpr int i = getsize_2(); void constexprTest(){<!-- --> int j = i; // initialized using non-const object int k = getsize(); // initialized using constant expression }
The assembly code is obtained as follows:
constexprTest() # @constexprTest() # ?.0: push rbp mov rbp, rsp sub rsp, 16 mov dword ptr [rbp - 4], 20 # Directly replace with 20 call getsize_2() # You need to call the function to determine the value of j mov dword ptr [rbp - 8], eax add rsp, 16 pop rbp ret # -- End function
3. File scope of constant objects
Constants are generally only valid within the file in which they are defined. To define it in one file, declare it and use it in other files, you can use the extern
keyword.
// a.cpp extern const int size = 20; // b.h extern const int size; // Statement, it is the same constant object as a.cpp
4. Constant reference
A reference bound to a const object is called a constant reference (
r
e
f
e
r
e
n
c
e
reference
reference
t
o
to
to
c
o
n
s
t
const
const).
const i = 0; const & amp;j = i; // reference to const
4.1 Reference to non-constant objects
In the above example, we created a reference bound to a const object. A constant reference can also be bound to a non-const object. Like a const object, this reference cannot change the bound object while the program is running.
int i = 20; const int &j = i; j = 21; // error: cannot assign to variable 'j' // with const-qualified type 'const int & amp;'
4.2 Reference literals
Interestingly, constant references can refer to literals, but constant references cannot.
const int & amp;i = 20; // correct int & amp;j = 20; // error: non-const lvalue reference to type // 'int' cannot bind to a temporary of type 'int'
Let's write a program and compile it to see the principle.
void constReference(){<!-- --> const int &i = 20; }
The assembly code is as follows:
constReference(): # @constReference() # ?.0: push rbp mov rbp, rsp mov dword ptr [rbp - 12], 20 # Temporary object lea rax, [rbp - 12] mov qword ptr [rbp - 8], rax # Reference the temporary object pop rbp ret # -- End function
It can be seen that the program first creates a temporary object (unnamed object) 20 on the stack space, and then obtains the address of the temporary object to reference it.
5. Pointer constants and constant pointers
This is a basic but relatively classic knowledge point. But I found that the explanations of these two on the Internet are opposite to those on cpp primer. This is a matter of translation, it has nothing to do with right or wrong. I personally prefer what is said online. In addition, I think it should be understood more clearly when combined with English.
5.1 Constant pointer (pointer to const)
A constant pointer is a pointer that points to a constant. Just like you cannot use non-const references to bind constants, if you want to store the address of a constant object, you must also use a pointer with the so-called constant qualified type const-qualified
.
const int i = 5; const int *p = & amp;i; // pointer constant
const int
and int
should be considered two different types. Because the pointer type must match the type of the object it points to, an error occurs when initializing a constant pointer with the address of a non-constant object.
int i = 5; const int *p = & amp;i; // cannot initialize a variable of type // 'const int *' with an lvalue of type 'int'
5.2 Pointer constant (const pointer)
int i = 5; int *const p = & amp;i;
Recall the principle of proximity mentioned in the previous article. The const
qualifier is closest to the variable name p
, so p
is first a constant, and secondly A pointer to an object of type int
. The constant type makes it impossible to change the value of the pointer after initialization, that is, it cannot point to other objects.
The above two can also be used nested, for example:
const int i = 5; const int *const p = & amp;i;
At this time, p
is a pointer constant pointing to an object of type const int
.
In addition, combined with this nested scenario, two terms are proposed in cpp primer, which will be frequently used in the future.
- Top-level const: The pointer itself is a constant.
- Underlying const: The object pointed to by the pointer or bound by the reference is a constant.