Summary of C++ const usage

Time: 202205232202


constexpr usage summary

Constants and their definitions

Constants are fixed values ​​that do not change during program execution. These fixed values ​​are also called literals. Constants can be of any basic data type, including integer numbers, floating-point numbers, characters, strings, and booleans. Constants are like regular variables, except that the value of the constant cannot be modified after it is defined.

int a = 5;   //  5 is the constant
cout << "Hello World " // Hello World string is a constant

Two ways to define constants

//macro constant                 
#define MAX 100
// const keyword           
const int max = 100;

Difference between const constant and macro constant

  • There are type safety checks when const is used, and macro constants are directly replaced when used

  • const saves more memory space

#define PI 3.14159   
const doulbe  Pi=3.14159;  //At this time, the Pi is not put into the ROM(Read-Only Memory), only in the read-only register
double i=Pi;   //Allocate memory for the Pi at this point, not later!
double I=PI;  //Macro substitution during compilation, memory allocation
double j=Pi;  //no memory allocation
double J=PI;  //Perform macro replacement again, and allocate memory again!
  • Macro constants can be canceled
#define PI 3.14159 
#undef PI 3.14159   
double I=PI;         // Error Undefined identifier PI	

const modified reference

const is to modify a data as a constant, and "reference" is to give an alias to a variable, which acts as a pointer, but it is easier to operate than a pointer. In C++ development, in order to achieve "changes in formal parameters, changes in actual parameters" , the parameter can be defined as a reference. However, sometimes, in order to protect the formal parameter from being modified in the function, we can define the formal parameter reference as a const type.

const int& rx = x;

const modified pointer

Use the code example as follows

const int* a1 = new int(10);
int const* a2 = new int(10);

a1 = new int(20); // Do not modify the content, directly assign the new value
*a1 = 20; // error expression must be a modifiable lvalue  
// and the original formula restricts the content pointed to and cannot be modified

a2 = new int(30);// Do not modify the content, directly assign the new value
*a2 = 20;// The error is the same as above In fact, the writing effect of a1 and a2 is the same

int* const a3 = new int(10);
const int* const a4 = new int(10);

a3 = new int(30);  // Report an error as above
 *a3 = 30; // assign new value directly

a4 = new int(30); // Report an error as above
*a4 = 40;// Error cannot be changed

As can be seen from the above example, some values ​​can be modified, and some values ​​cannot be modified. How to judge in actual use? Bjarne gives a mnemonic method in his The C++ Programming Language: read a declaration from right to left. ( * read as pointer to )

// Read as a1 is pointer to int const means that the value of int is const unchanged
const int* a1 
// Read as a3 const is pointer to int means that the pointer of a3 is const unchanged
int* const a3 

The conclusion is that whoever is close to const cannot change it

location of const variable in memory

After the simple use of const-modified references and pointers, there must be doubts. At the beginning, is const not defining variables as constants? So why even change it?
In fact, the const-modified quantity is not a constant, but a read-only quantity. The value assigned to the const variable is all replaced at compile time, and the const variable can be modified through memory at runtime. Make the following two explanations
(1) The const variable located in the stack area can be modified through the memory (pointer), the syntax is compliant, and the compilation and operation will not report an error, but all the places where the constant is used are replaced with the value given at the time of definition when compiling. , then the value modified by the pointer cannot be used at runtime.
(2) Modify the const variable located in the static storage area through the memory (pointer), there is no syntax error, the compilation will not error, and an exception will be reported once it runs.

const only guarantees invariance when the constant is used at compile time, not runtime behavior. Programmers will get a compile error if they modify the constant directly, but if the memory is modified using an indirect pointer, they won't get any errors and warnings as long as the syntax is compliant. Because the compiler can't know whether you modify it intentionally or unintentionally, but since it is defined as const, the programmer should not modify it, or directly use the variable definition, the sample code is as follows

const int a = 1;
void test()
{
 	const int c = 3;
 	int* p = (int*)& c;
 	*p = 4;
 	//When compiling, c is replaced by 3, and the value modified by memory cannot be used
 	//*p represents the modified value of c
 	cout << c << " " << *p << endl;  // Output 3 4 but when you debug, c is displayed as 4
  	p = (int*)& a;
 	//When compiling, a is replaced with 1, and p points to the address of a
 	cout << c << " " << *p << endl;  // output 3 1
 	//Modify the const variable located in the static storage area, compile without error, and an exception will be reported when running
	 *p = 4;
}

Summary: const-modified variables are "read-only" and cannot modify their value through the variable itself, but can be modified indirectly through pointer references, etc.

const volatile

Variables modified by const volatile can not completely replace the value assigned by the const volatile variable at compile time, so the value modified by memory can be used at runtime:
(1) The const volatile variable located in the stack area can be modified through memory (pointer)
(2) Modify the const volatile variable located in the static storage area through the memory (pointer), the syntax and compilation do not report errors, and the operation error is abnormal.
The sample code is as follows

const int b = 1;
void test2()
{
 const volatile int c = 3;
 //A variable modified by const volatile will only use the value assigned at the time of initialization at runtime
 //When compiling, const volatile modified variables are not replaced
 cout << c << endl;       // output 3  
 void* p = (void*)&c;
 (*(int*)p) = 4;
//Modify the value of c to 4
 cout << c << endl;  // Output 4 means that the value of c has been changed
 p = (void*)& b;
 //Modifying the const volatile variable in the static storage area at runtime does not compile without error, but reports an error when running
 (*(int*)p) = 5;
 cout << b << endl;
 } 

Use of const in classes

Initialize constant member variables: they are constants during the lifetime of an object, and const constants can only be initialized by means of an initialization list.

class Test
{
public:
    const int a;
    Test(int i):a(i){}
}

Modified function parameters: add const before the incoming parameters, indicating that the incoming parameters cannot be modified

void fun0(const Test* p_test);
void fun1(const Test& test);
void fun1(Test test);

Modified member function: Adding const after the member function name indicates that the function is a constant member function. The const of the constant member function implicitly modifies the this pointer, that is, the object cannot be modified, so the constant member function can only access member variables, but cannot be modified. Only other constant member functions can be called.

int g_a;
void g_fun(){}
class Test
{
public:
    void fun0(){}
    void fun1() const{} 
    void fun2() const
    {
        a = 10;//Error, "must be a modifiable lvalue"
        fun0();//error, object contains a type qualifier that is incompatible with member function
        fun1();//Normal, other constant member functions can be called
        g_a = 10;//normal
        g_fun();//normal
        m_b = 10; // Special can be modified
    }
private:
        int a;
        mutable int m_b; // mutalbe and const are antonyms, and they can be modified by adding keywords
}

Modified function return value: When using const Test* fun1(); to return a pointer, the return value can only be assigned to a const-modified pointer of the same type.

class Test
{
public:
    void fun0(){}
    const Test fun1(){
        return *this;
    }
    const Test* fun2(){
        return this;
    }
};
int main()
{
      Test test;
      Test r = test.fun1();
      const Test* rp = test.fun2();  // Pay special attention when returning pointers
      Test* rp = test.fun2(); // Error const Test* type cannot be used to initialize an entity of type Test*
}

Tags: C++

Posted by CGRRay on Tue, 24 May 2022 00:45:05 +0300