C++ const reference pointer

Posted by kingman65 on Mon, 16 Sep 2019 06:02:54 +0200

First, briefly recall the nature of a constant:

int main()
{
    const int buffSize = 512;
    buffsize = 512; //X buffSize is constant
}

At initialization:

const int i = get_val();    //_Runtime Initialization
const int j = 42;           //_compile-time initialization
const int k;                //XK uninitialized

When one object is used to initialize another, it doesn't matter whether they are const or not

int i = 42;
const int ci = i;
int j = ci;

ci is a reshaping constant, but the constant characteristics of ci only work when performing operations that change ci

const and reference

A reference to a constant

Binding a reference to a const object is called a reference to a constant

A reference to a constant cannot be used as an object to modify its binding. References and the objects they reference are constants

const int ci = 1024;
const int &r1 = ci;

Note that:

const int ci = 1024;
const int &r1 = ci;
r1 = 42;        //X r1 is a reference to a constant
int &r2 = ci;   //XR2 is a constant reference and ci is a constant object

Because ci is not allowed to be used as an object to modify its binding, it cannot be altered by reference (assuming the fourth sentence is legal, we can alter ci by r2, which is obviously incorrect)

The following two sentences are the same

int &r3 = r1;       //×
const int &r4 = r1; //√

What we say orally is a reference to const. Strictly, there is no constant reference because, unlike pointers, a reference is not an object, and there is no way for the reference itself to remain constant.

(P.S: Since C++ does not allow arbitrary changes to the objects bound by references, it can also be understood that all references are constants. Of course, whether or not the referenced objects are constants will determine the actions they can take part in, but in no case will the binding relationship between references and objects be affected)

Initialize references to constants

We know that the type of reference must be the same as the type of object referenced, but there is a second exception to references involving initialization constants (first: initialization constants references allow any expression to be used as an initial value, as long as the expression can be converted to the type of reference)

int i = 42;
const int &r1 = i;      //_Allow const int to be bound to a normal int object
const int &r2 = 42;     //_r2 is a constant reference
const int &r3 = r1 * 2; //_r3 is a constant reference
int &r4 = r1 * 2;       //X r4 is a common nonconstant reference

Why is this happening?Let's start with a simple example

double dval = 0.114514;
const int &ri = dval;
cout << "ri = " << ri <<endl;

Run Output

ri=0

In this process, the compiler actually changes the code to:

double dval = 0.114514;
const int temp = dval;
const int &ri = temp;
cout << "ri = " << ri <<endl;

In this case, ri binds a temporary object, so you can see what happened to the code above.

You can imagine the consequences of performing the above initialization if RI is not a constant: if RI is not a constant.Allow assignments to ri, which will change the value of the object that RI refers to (at this point binding a temporary amount instead of a dval), so C++ also classifies the following as illegal

double dval = 0.114514;
int &ri = dval;     //×
cout << "ri = " << ri <<endl;

Also note that a reference to const may refer to an object that is not a const

A reference to a const restricts only the operations in which the reference can participate, and whether the reference object itself is a constant, so the object may also be a non-constant, allowing its value to be changed in other ways

int i = 42;
int &r1 = i;
const int &r2 = i;
//r2 = 0; //*r2 is a constant reference
cout << "r2 = " << r2 <<endl;
i = 0;
cout << "r2 = " << r2 <<endl;

The program output is as follows:

r2 = 42
r2 = 0

const and pointer

pointer to const

Like a reference to a constant, a pointer to a constant cannot be used to change the value of the object it refers to

At the same time, to store the address of a constant object, you can only use a pointer to the constant:

const double homo = 1.14;
double *ptr = &homo;            //X ptr is a normal pointer
const double *cptr = &homo;     //√
cptr = 5.14                     //X cannot assign *cptr

Unlike references, we can change what the pointer to a constant points to

const double homo = 1.14;
const double *cptr = &homo;
cout << "cptr = " << *cptr <<endl
const double homo2 = 5.14;
cptr = &homo2;  
cout << "cptr = " << *cptr <<endl;
//Allow a pointer to a constant to point to a non-constant object

Note that, like references, although we say that the type of pointer must be the same as the object being pointed to, there is one exception here: Allow a pointer to a constant to point to a non-constant object

const double homo = 1.14;
const double *cptr = &homo;
double dval = 3.14;
cptr = &dval;   //Allow a pointer to a constant to point to a non-constant object
*cptr = 0.0     //However, it is not allowed to modify the value of a non-constant object by pointing to a constant

Therefore, a pointer to a constant does not specify that the object it refers to must be a constant. A pointer to a constant only requires that the value of the object it refers to cannot be modified through the pointer, but does not specify that the value of the object it refers to cannot be changed through other means.

const double homo = 1.14;
const double *cptr = &homo;
cout << "cptr = " << *cptr <<endl

double dval = 5.14;
cptr = &dval;   //Allow a pointer to a constant to point to a non-constant object
//*cptr = 0.0 //but it is not allowed to modify the value of a non-constant object by pointing to a constant
cout << "cptr = " << *cptr <<endl;

dval = 0.0      //The value of the specified object can be changed in other ways
cout << "cptr = " << *cptr <<endl;

Now our output becomes:

cptr = 1.14
cptr = 5.14
cptr = 0

const pointer

Unlike references, the pointer itself is an object, so it is allowed to set the pointer itself as a constant, that is, a constant pointer, which must be initialized, and the value (the address stored in the pointer object) cannot be changed after initialization is complete.

Before placing the *const keyword, the pointer is a constant (that is, the value of the pointer itself is unchanged)

int errorNumb = 0;
int* const curErr = &errorNumb; //curErr is a constant pointer, pointing all the way to errNumb
const double pi = 3.1415;
const double* const pip = &pi;  //pip is a constant pointer to a constant object

The following two styles differ greatly:

int* const curErr = &errorNumb; //curErr always points to errNumb
*curErr = 1;                    //The value of the specified variable can be modified
const int* curErr = &errorNumb; //curErr is a pointer to a constant
*curErr = 1;                    //X cannot modify the value of the specified object through curErr

Top and bottom const s

Since the pointer itself is an object and it can point to another object, whether the pointer itself is a constant and what the pointer refers to is a constant or not are two independent issues. The top const indicates that the pointer itself is a constant, and the bottom const indicates that the object the pointer refers to is a constant.

The top const actually represents any object (itself) as a constant, and the pointer style is special because it can be either the top or the bottom const

int i = 0;
int* const p1 = &i;         //p1 itself is constant, top const
const int ci = 42;          //ci itself is constant, top const
const int* p2 = &ci;        //*After const, p2 is a pointer to a constant, underlying const
const int* const p3 = p2;   //First look at the top on the left, then the bottom on the right, p3 is a constant pointer to a constant
const int& r = ci;          //Declares that all references to consts are underlying consts, and r is a reference to a constant

The copy operation does not affect the value of the copied object, and the top const is not affected

i = ci;
p2 = p3;

However, the lower const has limitations:

When copying operations, the objects being copied and copied must have the same underlying const qualifications, and the data types of the two living objects can be converted (non-constants can be converted to constants, not vice versa).

int* p = p3;        //X p3 contains bottom const, p does not
const int* p = p3;  //_p and p3 are bottom const s
p2 = p3;            //_p2 and p3 are bottom const s
p2 = &i;            //_int can be converted to const int*
int& r = ci;        //X plain int&cannot be bound to const int&
const int& r2 = i;  //_const int&can be bound to a normal int

Topics: C++ pip