There are many articles on the Internet that discuss the differences between C ++'s "reference" and "pointer". When talking about the differences, one of them is: "reference cannot be blank (NULL ), references must be associated with valid storage units, and pointers can be NULL) ". However, in practice, sometimes we leave this rule aside to maintain consistency, creates an empty reference ".
In many cases, "empty references" can indeed work, so that "reference cannot be empty" advice is ridiculed as formalism, just as a sensational standard maker. An example of "null reference" is:
[Cpp]
Int * a = NULL;
Int & B = *;
Int * a = NULL;
Int & B = * a; when B is accessed, the program exception occurs:
[Cpp]
Void f (int & p)
{
P = 0;
}
F (B );
Void f (int & p)
{
P = 0;
}
F (B); of course, you can add some judgments to correct this problem:
[Cpp]
Void f (int & p)
{
If (& p) p = 0;
}
Void f (int & p)
{
If (& p) p = 0;
}
How are you doing? However, if you change to a pointer, the number of characters you want to enter is exactly the same:
[Cpp]
Void f (int * p)
{
If (p) * p = 0;
}
Void f (int * p)
{
If (p) * p = 0;
} So, whether to use "reference" or "pointer" seems to be something that the wise sees the wise and the benevolent sees the benevolence.
However, however ......
Is that true?
Let's take a look at the complex example:
[Cpp]
// Test. cpp
# Include <iostream>
Class
{
Int;
};
Class B
{
Int B;
};
Class C
: Public A, public B
{
Int c;
};
Void fb (B & B)
{
Std: cout <& B <std: endl;
}
Void fb (B * B)
{
Std: cout <B <std: endl;
}
Int main (int argc, char * argv [])
{
C * c = NULL;
Fb (c );
Fb (* c );
Return 0;
}
// Test. cpp
# Include <iostream>
Class
{
Int;
};
Class B
{
Int B;
};
Class C
: Public A, public B
{
Int c;
};
Void fb (B & B)
{
Std: cout <& B <std: endl;
}
Void fb (B * B)
{
Std: cout <B <std: endl;
}
Int main (int argc, char * argv [])
{
C * c = NULL;
Fb (c );
Fb (* c );
Return 0;
}
Compile and run it to see:
[Plain]
$./Test
0
0x4
$./Test
0
0x4 bytes. if & B is not 0, it is not "null reference". At this time, even if the judgment is added, if (& B) will not help.
You may have noticed that the above is run in the linux environment. What about the windows environment:
[Plain]
> Test.exe
00000000
00000000
> Test.exe
00000000
00000000 at this time, "null reference" maintains its "null" attribute. It is relieved to be a C ++ developer only on the windows platform.
What is the problem? Your eyes have cheated you? Maybe yes, but the CPU won't cheat us. The essence can be seen from the assembly code. The Code compiled on the linux platform is as follows:
[Plain]
Dump of worker er code for function main:
0x0804870a <+ 0>: push % ebp
0x0804870b <+ 1>: mov % esp, % ebp
0x0804870d <+ 3>: and $0xfffffff0, % esp
0x08048710 <+ 6>: sub $0x20, % esp
0x08048713 <+ 9>: movl $0x0, 0x1c (% esp)
0x08000001b <+ 17>: cmpl $0x0, 0x1c (% esp)
0x08048720 <+ 22>: je 0x8000002b <main + 33>
0x08048722 <+ 24>: mov 0x1c (% esp), % eax
0x08048726 <+ 28>: add $0x4, % eax
0x08048729 <+ 31>: jmp 0x8048730 <main + 38>
0x08000002b <+ 33>: mov $0x0, % eax
0x08048730 <+ 38>: mov % eax, (% esp)
0x08048733 <+ 41>: call 0x80486df <fb (B *)>
0x08048738 <+ 46>: mov 0x1c (% esp), % eax
0x08000003c <+ 50>: add $0x4, % eax
0x0804253f <+ 53>: mov % eax, (% esp)
0x08048742 <+ 56>: call 0x80486b4 <fb (B &)>
0x08048747 <+ 61>: mov $0x0, % eax
0x0801_4c <+ 66>: leave
0x0801_4d <+ 67>: ret
Dump of worker er code for function main:
0x0804870a <+ 0>: push % ebp
0x0804870b <+ 1>: mov % esp, % ebp
0x0804870d <+ 3>: and $0xfffffff0, % esp
0x08048710 <+ 6>: sub $0x20, % esp
0x08048713 <+ 9>: movl $0x0, 0x1c (% esp)
0x08000001b <+ 17>: cmpl $0x0, 0x1c (% esp)
0x08048720 <+ 22>: je 0x8000002b <main + 33>
0x08048722 <+ 24>: mov 0x1c (% esp), % eax
0x08048726 <+ 28>: add $0x4, % eax
0x08048729 <+ 31>: jmp 0x8048730 <main + 38>
0x08000002b <+ 33>: mov $0x0, % eax
0x08048730 <+ 38>: mov % eax, (% esp)
0x08048733 <+ 41>: call 0x80486df <fb (B *)>
0x08048738 <+ 46>: mov 0x1c (% esp), % eax
0x08000003c <+ 50>: add $0x4, % eax
0x0804253f <+ 53>: mov % eax, (% esp)
0x08048742 <+ 56>: call 0x80486b4 <fb (B &)>
0x08048747 <+ 61>: mov $0x0, % eax
0x0801_4c <+ 66>: leave
0x0801_4d <+ 67>: ret
This is for windows:
[Plain]
Wmain:
004114D0 push ebp
004114D1 mov ebp, esp
004114D3 sub esp, 0DCh
004114D9 push ebx
004114DA push esi
004114DB push edi
004114DC lea edi, [ebp-0DCh]
004114E2 mov ecx, 37 h
004114E7 mov eax, 0 CCCCCCCCh
004114EC rep stos dword ptr es: [edi]
004114EE mov dword ptr [c], 0
004114F5 mov eax, dword ptr [c]
004114F8 mov dword ptr [rc], eax
004114FB cmp dword ptr [c], 0
004114FF je wmain + 3Fh (41150Fh)
00411501 mov eax, dword ptr [c]
00411504 add eax, 4
00411507 mov dword ptr [ebp-0DCh], eax
0041150D jmp wmain + 49 h (411519 h)
0041150F mov dword ptr [ebp-0DCh], 0
00411519 mov ecx, dword ptr [ebp-0DCh]
0041151F push ecx
00411520 call fb (411118 h)
00411525 add esp, 4
00411528 cmp dword ptr [rc], 0
0041152C je wmain + 6Ch (41153Ch)
0041152E mov eax, dword ptr [rc]
00411531 add eax, 4
00411534 mov dword ptr [ebp-0DCh], eax
0041153A jmp wmain + 76 h (411546 h)
0041153C mov dword ptr [ebp-0DCh], 0
00411546 mov ecx, dword ptr [ebp-0DCh]
0041154C push ecx
0041154D call fb (41108Ch)
00411552 add esp, 4
00411555 xor eax, eax
00411557 pop edi
00411558 pop esi
00411559 pop ebx
0041155A add esp, 0DCh
00411560 cmp ebp, esp
00411562 call @ ILT + 345 (_ RTC_CheckEsp) (41115Eh)
00411567 mov esp, ebp
00411569 pop ebp
0041156A ret
Wmain:
004114D0 push ebp
004114D1 mov ebp, esp
004114D3 sub esp, 0DCh
004114D9 push ebx
004114DA push esi
004114DB push edi
004114DC lea edi, [ebp-0DCh]
004114E2 mov ecx, 37 h
004114E7 mov eax, 0 CCCCCCCCh
004114EC rep stos dword ptr es: [edi]
004114EE mov dword ptr [c], 0
004114F5 mov eax, dword ptr [c]
004114F8 mov dword ptr [rc], eax
004114FB cmp dword ptr [c], 0
004114FF je wmain + 3Fh (41150Fh)
00411501 mov eax, dword ptr [c]
00411504 add eax, 4
00411507 mov dword ptr [ebp-0DCh], eax
0041150D jmp wmain + 49 h (411519 h)
0041150F mov dword ptr [ebp-0DCh], 0
00411519 mov ecx, dword ptr [ebp-0DCh]
0041151F push ecx
00411520 call fb (411118 h)
00411525 add esp, 4
00411528 cmp dword ptr [rc], 0
0041152C je wmain + 6Ch (41153Ch)
0041152E mov eax, dword ptr [rc]
00411531 add eax, 4
00411534 mov dword ptr [ebp-0DCh], eax
0041153A jmp wmain + 76 h (411546 h)
0041153C mov dword ptr [ebp-0DCh], 0
00411546 mov ecx, dword ptr [ebp-0DCh]
0041154C push ecx
0041154D call fb (41108Ch)
00411552 add esp, 4
00411555 xor eax, eax
00411557 pop edi
00411558 pop esi
00411559 pop ebx
0041155A add esp, 0DCh
00411560 cmp ebp, esp
00411562 call @ ILT + 345 (_ RTC_CheckEsp) (41115Eh)
00411567 mov esp, ebp
00411569 pop ebp
0041156A ret
I am interested in researching assembly code.
Looking back, the two compiler Processing Methods on both platforms have their own rationality. The windows platform has increased fault tolerance, while the linux platform has reduced judgment and increased performance when processing references. This implicitly reflects the differences between windows and linux development concepts.
Finally, remember that the reference cannot be empty. If there may be null objects, use pointers.