[cpp primer essay] 03. Constants

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 other constexpr.
  • 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.
syntaxbug.com © 2021 All Rights Reserved.