Original article link
Pointers and references are quite different in form, but they all seem to have the same functionality and can directly reference objects and perform direct operations on them. But when should I use pointers? When can I use references? The two are easy to confuse. Here I will introduce pointers and references in detail, and strive to present the most authentic aspect to everyone. If I'm not good enough, I 'd like to show my bid and keep my bid, please give me some advice. If it feels good, Please applaud.
1. pointer and reference definition
Before in-depth introduction, let's take a look at the definitions of pointers and references, the differences between pointers and references, and then discuss the differences between pointers and references in depth.
- Authoritative pointer definition:
In a declarationT dWhereDHas the form *CV-qualifier-seqOPT D1 And the type of the identifier in the DeclarationT d1Is"Derived-declarator-type-listT ", then the type of the identifierDIs"Derived-declarator-type-list CV-qualifier-seqPointer to T". The CV-qualifiers apply to the pointer and not to the object pointer. -- Excerpt from ansi c ++ Standard Note: Some readers may not understandCV-qualifier-seq
- CV-qualifiers (CV qualifier)
There are three types of CV-qualifiers: const-qualifier (const qualifier), volatile-qualifier (volatile qualifier), and const-volatile-qualifier (const-volatile qualifier ).
The non-static, non-mutable, and non-referenced data members of the const class object are const-qualified; The non-static and non-referenced data member of the volatile class object is volatile-qualified;
The non-static and non-referenced data member of the const-volatile class object is const-volatile-qualified.
When CV-qualifiers is used to limit the array type, the array member is actually limited by the CV-qualifiers instead of the array type.
The composite type is not limited by the CV-qualifier because its members are limited by the CV-qualifier. That is to say, even if the composite type members are limited by the CV-qualifier, this composite type is not a CV-qualified object.
|
- Reference authoritative definition:
In a declarationT dWhere D has the form &D1 And the type of the identifier in the DeclarationT d1Is"Derived-declarator-type-listT ", then the type of the identifierDIs"Derived-declarator-type-list CV-qualifier-seqReference to T". CV-qualified references are ill-formed when T when the CV-qualifiers are introduced through the use of a typedef or a template type argument, in which case the CV-qualifiers are ignored. -- Excerpt from ansi c ++ Standard |
The above definition is hard to understand. If so, it means you are not familiar with C ++, and you still have a long way to go. The following is a brief introduction:
- Pointer-for a type T, T * is the pointer type pointing to T, that is, a T * type variable can save the address of a t object, type t can be added with some restrictions, such as const and volatile. See the following figure for pointer meanings:
- Reference-a reference is an alias of an object. It is mainly used for function parameters and return value types. The symbol X & indicates a reference of the X type. See, for the meaning of the reference:
2. Differences between pointers and references
-
- First, the reference cannot be null, but the pointer can be null. As mentioned above, the reference is the alias of an object, and the reference is null. -- the object does not exist. How can I have an alias! Therefore, Initialization is required when defining a reference. Therefore, if you have a variable that is used to point to another object, but it may be null, you should use a pointer. If the variable always points to an object. E ., variables cannot be empty in your design. You should use references. For example, if a reference variable is defined, the compilation will fail if it is not initialized (an error occurs during compilation ):
The declared pointer can not point to any object. It is precisely for this reason that,The pointer must be empty before it can be used..
- Second, the reference cannot change the direction of an object, but the pointer can change and point to other objects. Note: although the reference cannot change the point, it can change the content of the initialization object. For example, for a ++ operation, the referenced operation directly reflects the object to which it points, rather than changing the point. The operation on the pointer will direct the pointer to the next object, instead of changing the content of the object. See the following Code :
# Include<Iostream>
Using NamespaceSTD;
IntMain (IntArgc,Char** Argv)
{
IntI = 10;
Int& Ref = I;
Ref ++;
Cout <"I ="<I <Endl;
Cout <"Ref ="<Ref <Endl;
IntJ = 20;
Ref = J;
Ref ++;
Cout <"I ="<I <Endl;
Cout <"Ref ="<Ref <Endl;
Cout <"J ="<J <Endl;
Return0;
}
The ++ operation on Ref directly reflects the variable to be referred to, and reassigns "ref = J" to the referenced variable ref, which does not change the direction of ref. It still points to I, instead of J. Of course, performing the ++ operation on the ref will not affect J. If these are pointers, the situations are very different. Please experiment on your own. The output result is as follows:
-
- Again, the reference size is the size of the variable pointed to, because the reference is just an alias; the pointer is the size of the pointer, 4 bytes. See:
We can also see from the above:References are more beautiful than pointers. You can use reference variable names between referenced content instead of pointer content *; when defining a reference, you do not need to use & access like a pointer.
-
- Finally, the reference is safer than the pointer. Since there is no null reference, and the reference is initialized to point to an object, it cannot be changed to another object reference, so the reference is safe. A pointer can point to another object at any time without being initialized or null, so it is not safe. Although the const pointer cannot be changed, there is still a null pointer, and it may generate a wild pointer (that is, multiple pointers direct to a memory, after one pointer is free, other pointers become wild pointers ).
All in all, in short, all these differences can be attributed"The Pointer Points to a piece of memory. Its content refers to the memory address, and the reference is the alias of a piece of memory. The reference does not change to the point."
3. Special const
Why should I mention the const keyword here? Because const imposes different limitations on pointers and references, let me see them one by one.
- Constant pointer vs constant reference
Constant pointer: a pointer to a constant. Add const before the type of the pointer Definition Statement to indicate that the object to which the pointer is a constant.
Defining a pointer to a constant only limits the indirect access operation of the pointer, but does not specify the Operation Specifications of the value itself pointed to by the pointer.
The constant pointer definition "const int * pointer = & A" tells the compiler that * pointer is a constant and cannot operate * pointer as the left value.
Constant reference: refers to the reference of a constant. Add const before the type of the referenced Definition Statement to indicate that the object pointing to is a constant. Just like pointers, you cannot use references to re-assign values to variables.
- Pointer constant vs reference constant
Add const before the pointer name of the pointer Definition Statement to indicate that the pointer itself is a constant. Initialization is required when defining pointer constants! This is a natural attribute for reference. You do not need to reference the reference name of the pointer Definition Statement before adding Const.
The pointer constant definition "int * const pointer = & B" tells the compiler that pointer is a constant and cannot be operated as the left value. However, indirect access values can be modified, that is, * pointer can be modified.
- Constant pointer constant vs constant reference constant
Constant pointer constant: A pointer constant pointing to a constant. You can define a pointer constant pointing to a constant. It must be initialized during definition. The constant pointer constant definition "const int * const pointer = & C" tells the compiler that both pointer and * pointer are constants and cannot be operated as left values.
The so-called "constant reference constant" does not exist, because the reference variable is a reference constant just as mentioned above. C ++ does not distinguish between the const reference of a variable and the reference of a const variable.ProgramYou must not assign a value to the reference itself to direct it to another variable. Therefore, the reference is always Const. If the reference application keyword const is used, the target is called the const variable. No: const double const & A = 1; only const double & A = 1;
Conclusion: There is a rule that can distinguish whether const modifies the pointer or the data pointed to by the pointer-draw an asterisk (*) Vertically passed through the pointer declaration. If const appears on the left, the Pointer Points to a constant. If the const appears on the right, the pointer itself is a constant. The reference itself is a constant, that is, it cannot be changed.
4. Implementation of pointers and references
We use the following simple code to analyze pointers and references in depth:
# Include<Iostream>
Using NamespaceSTD;
IntMain (IntArgc,Char** Argv)
{
IntI = 1;
Int& Ref = I;
IntX = ref;
Cout <"X is"<X <Endl;
Ref = 2;
Int* P = & I;
Cout <"Ref ="<Ref <", I ="<I <Endl;
}
Use the above CodeG ++ test. cCompile and decompileObjdump-d a. OutTo obtain the assembly code of the main function:
08048714 <main>: 8048714: 55 push % EBP 8048715: 89 E5 mov % ESP, % EBP 8048717: 83 E4 F0 and $0xfffffff0, % ESP// Reserved location for the parameters argc and argv of the Main Function 80100001a: 56 push % ESI 80100001b: 53 push % EBX 80100001c: 83 EC 28 sub $0x28, % ESP 80100001f: C7 44 24 1C 01 00 00 movl $0x1, 0x1c (% ESP)// Store 0x1 in the ESP register, that is, int I = 1 8048726: 00
8048727: 8d 44 24 1C Lea 0x1c (% ESP), and the address of variable I in % eax // ESP register is sent to eax 80100002b: 89 44 24 18 mov % eax, 0x18 (% ESP) // pass the content (I address) in the register eax to the variable ref in the register, that is, Int & ref = I 804872f: 8B 44 24 18 mov 0x18 (% ESP), % eax// Pass the ref in the ESP register to eax, that is, the I address. 8048733: 8B 00 mov (% eax), % eax// Take the value in the register eax as the address and obtain the value to eax8048735: 89 44 24 14 mov % eax, 0x14 (% ESP)// Pass the value in register eax to X in register ESP, that is, x = ref 8048739: C7 44 24 04 00 89 04 movl $0x8048900,0x4 (% ESP) 8048740: 08 8048741: C7 04 24 40 A0 04 08 movl $0x804a040, (% ESP) 8048748: E8 CB Fe FF call 8048618 <_ zstlsist11char_traitsiceerst13basic_ostreamict_es5_pk@ PLT> 803664d: 8B 54 24 14 mov 0x14 (% ESP), % edX 8048751: 89 54 24 04 mov % edX, 0x4 (% ESP) 8048755: 89 04 24 mov % eax, (% ESP) 8048758: E8 5B Fe FF call 80485b8 <_ znsolsei @ PLT> 804875d: C7 44 24 04 38 86 04 movl $0x8048638,0x4 (% ESP) 8048764: 08 8048765: 89 04 24 mov % eax, (% ESP) 8048768: E8 BB Fe FF call 8048628 <_ znsolsepfrsos_e @ PLT>// From 8048739 ~ 8048768 these rows are executed"Cout <"X is"<X <Endl;" 803666d: 8B 44 24 18 mov 0x18 (% ESP), % eax// Upload the ref in the ESP register to eax 8048771: C7 00 02 00 00 00 movl $0x2, (% eax)// Store 0x2 in the eax register 8048777: 8d 44 24 1C Lea 0x1c (% ESP), and the address of variable I in % eax // ESP register is sent to eax 804877b: 89 44 24 10 mov % eax, 0x10 (% ESP) // transfer the content in register eax (that is, the address of I) to P in register ESP 804877f: 8B 5C 24 1C mov 0x1c (% ESP), % EBX 8048783: 8B 44 24 18 mov 0x18 (% ESP), % eax 8048787: 8B 30 mov (% eax), % ESI 8048789: C7 44 24 04 06 89 04 movl $0x8048906,0x4 (% ESP) 8048790: 08 8048791: C7 04 24 40 A0 04 08 movl $0x804a040, (% ESP) 8048798: E8 7b Fe FF call 8048618 <_ zstlsist11char_traitsiceerst13basic_ostreamict_es5_pk@ PLT> 804879d: 89 74 24 04 mov % ESI, 0x4 (% ESP) 80347a1: 89 04 24 mov % eax, (% ESP) 80366a4: E8 0f Fe FF call 80485b8 <_ znsolsei @ PLT> 80366a9: C7 44 24 04 0d 89 04 movl $ 0x804890d, 0x4 (% ESP) 80366b0: 08 8010000b1: 89 04 24 mov % eax, (% ESP) 80366b4: E8 5f Fe FF call 8048618 <_ zstlsist11char_traitsiceerst13basic_ostreamict_es5_pk@ PLT> 80366b9: 89 5C 24 04 mov % EBX, 0x4 (% ESP) 80366bd: 89 04 24 mov % eax, (% ESP) 80366c0: E8 F3 fd ff call 80485b8 <_ znsolsei @ PLT> 80366c5: C7 44 24 04 38 86 04 movl $0x8048638,0x4 (% ESP) 80366cc: 08 8010000cd: 89 04 24 mov % eax, (% ESP) 80366d0: E8 53 Fe FF call 8048628 <_ znsolsepfrsos_e @ PLT>// These rows are executed"Cout <"Ref ="<Ref <", I ="<I <Endl;" 8010000d5: B8 00 00 00 00 mov $0x0, % eax 8010000da: 83 C4 28 add $0x28, % ESP 8010000dd: 5B pop % EBX 80366de: 5E pop % ESI 8010000df: 89 EC mov % EBP, % ESP 8010000e1: 5D pop % EBP 80366e2: C3 RET |
From the assembly code, we can see that the implementation of pointers and references in the compiler is the same:
8048727: 8d 44 24 1C Lea 0x1c (% ESP), % eax//The address of variable I in the ESP register is sent to eax.
803662b: 89 44 24 18 mov % eax, 0x18 (% ESP)// Pass the content (the address of I) in the register eax to the variable ref in the register, that is, Int & ref = I
8048777: 8d 44 24 1C Lea 0x1c (% ESP), % eax// Send the address of variable I in the ESP register to eax
804877b: 89 44 24 10 mov % eax, 0x10 (% ESP)// Transfer the content in register eax (that is, the address of I) to P in register ESP
Although pointers and references are implemented in the compilation process, the reference format is much more convenient and secure. Some people say :"A reference is just an alias and does not occupy memory space?"We can reveal this lie through this fact! In fact, references also occupy memory space.
5. pointer transfer and reference Transfer
To better understand pointers and references, we will introduce pointer passing and reference passing. How does a pointer and Reference Function Pass values? (The following section referencesDifferences Between Reference transfer and pointer transfer in C ++ (further sorting))
- A pointer passing parameter is essentially a value passing method, which transmits an address value. During the value transfer process, parameters in the form of the called function are processed as local variables of the called function, that is, the memory space is opened in the stack to store the values of the real parameters put in by the main function, it becomes a copy of the real parameter. The feature of value transfer is that any operation of the form parameter of the called function is performed as a local variable, without affecting the value of the real parameter variable of the main function.
- During the reference transfer process, the form parameter of the called function is also used as a local variable to open up the memory space in the stack, but the address of the real parameter variable stored by the main function is stored. Any operation of the called function on the form parameter is processed as indirect addressing. That is, the address stored in the stack is used to access the real variable in the main function. Because of this, any operation performed by the called function on the form parameter affects the real parameter variables in the main function.
Reference transfer and pointer transfer are different, although they are all a local variable in the space of the called function stack, however, any processing of referenced parameters will operate the relevant variables in the main function in an indirect addressing method. If you change the pointer address in the called function for pointer passing parameters, it will not affect the variables related to the main function. If you want to change the relevant variables in the main function by passing the pointer parameter, you must use a pointer to the pointer or pointer reference.
References
[1] The C ++ programming language (Special Edition), Bjarne stroustrup
[2] ansi c ++ Standard
[3] Assembly Language
: Wu Qin
Source: http://www.cnblogs.com/skynet/