Hay muchos artículos en Internet que discuten la diferencia entre "referencia" y "puntero" de C ++. Cuando se trata de la diferencia, uno de ellos es: "La referencia no puede ser NULL. La referencia debe estar asociada a una unidad de almacenamiento legal, y el puntero puede ser NULL". ) ", Pero en aplicaciones prácticas, a veces para mantener la coherencia, dejaremos de lado esta regla y crearemos artificialmente una" referencia nula ".
En muchos casos, las "referencias vacías" pueden funcionar, de modo que el consejo de que "las referencias no pueden estar vacías" es ridiculizado como formalismo, solo sensacionalismo por los creadores de estándares. Un ejemplo de una "referencia nula" es:
int * a = NULL; int & b = * a;
Entonces, al acceder a b, apareció la excepción del programa:
nulo f ( int & p) { p = 0 ; } f (b);
Por supuesto, puede agregar algo de juicio para solucionar este problema:
nulo f ( int & p) { if (& p) p = 0 ; }
¿Cómo es, es un poco incómodo? Pero si se reemplaza con un puntero, la cantidad de caracteres que desea ingresar es exactamente la misma:
nulo f ( int * p) { if (p) * p = 0 ; }
Entonces, si usar "referencia" o "puntero" parece ser una cuestión del sabio que ve al benevolente.
Sin embargo, sin embargo. . . . . .
¿Es esto realmente lo mismo?
Echemos un vistazo a un ejemplo más complicado:
// test.cpp #include <iostream> clase A { int a; }; clase B { int b; }; clase C : público A, público B { int c; }; nulo fb (B & b) { std :: cout << & b << std :: endl; } vacío fb (B * b) { std :: cout << b << std :: endl; } int main ( int argc, char * argv []) { C * c = NULL; fb (c); fb ( * c); devuelve 0 ; }
Compila y corre para ver:
$ ./ prueba 0 0x4
Oye, por qué & b no es 0, es decir, no es una "referencia nula". En este momento, incluso si se agrega el juicio, si (& b) no es útil.
Es posible que haya notado que lo anterior es el entorno de Linux, entonces, ¿qué pasa con el entorno de Windows:
> test.exe 00000000 00000000
En este momento, la "referencia vacía" mantiene su atributo "vacío", solo los desarrolladores de C ++ en la plataforma Windows pueden relajarse.
¿Qué está pasando? ¿Te están engañando tus ojos? Tal vez lo sea, pero la CPU no nos engañará, podemos ver la esencia del código de ensamblaje. El siguiente es el código compilado en la plataforma Linux:
Volcado del código del ensamblador para la función main: 0x0804870a <+ 0 >: push % ebp 0x0804870b <+ 1 >: mov % esp,% ebp 0x0804870d <+ 3 >: y $ 0xfffffff0,% esp 0x08048710 <+ 6 >: sub $ 0x20 ,% esp 0x08048713 <+ 9 >: movl $ 0x0,0x1c (% esp) 0x0804871b <+ 17 >: cmpl $ 0x0,0x1c (% esp) 0x08048720 <+ 22 >: je 0x804872b <main + 33 > 0x08048722 <+ 24 > : mov 0x1c (% esp),% eax 0x08048726 <+ 28>: agregar $ 0x4,% eax 0x08048729 <+ 31 >: jmp 0x8048730 <main + 38 > 0x0804872b <+ 33 >: mov $ 0x0,% eax 0x08048730 <+ 38 >: mov % eax, (% esp) 0x08048733 <+ 41 >: llame a 0x80486df <fb (B *)> 0x08048738 <+ 46 >: mov 0x1c (% esp),% eax 0x0804873c <+ 50 >: agregue $ 0x4,% eax 0x0804873f <+ 53 >: mov % eax, (% esp) 0x08048742 <++ 56>: llamar 0x80486b4 <fb (B &)> 0x08048747 <+ 61 >: mov $ 0x0,% eax 0x0804874c <+ 66 >: dejar 0x0804874d <+ 67 >: ret
Esto es para la plataforma de Windows:
wmain: 004114D0 empuje ebp 004114D1 mov ebp, esp 004114D3 sub esp, 0DCh 004114D9 empuje ebx 004114DA empuje esi 004114DB empuje edi 004114DC lea EDI, [ebp-0DCh] 004114E2 mov ecx, 37h 004114E7 mov eax, 0CCCCCCCCh 004114EC rep stos dword ptr es: [edi] 004114EE mov dword ptr [c], 0 004114F5 mov eax, dword ptr [c] 004114F8 movdword 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-0DCh1150D eax 004 jmp wmain + 49h (411519h) 0041150F mov dword ptr [ebp-0DCh], 0 00411519 mov ecx, dword ptr [ebp-0DCh] 0041151F push ecx 00411520 call fb (411118h) 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 [-0DCh ebp], eax 0041153A JMP wmain + 76H (411546h) 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 llamada @ ILT + 345 (__RTC_CheckEsp) (41115Eh) 00411567 mov esp, ebp 00411569 pop ebp 0041156A ret
El código de ensamblaje está interesado en estudiar solo, así que no entraré en detalles.
Mirando hacia atrás, los dos métodos de procesamiento de los compiladores de las dos plataformas tienen su razonabilidad: la plataforma Windows aumenta la tolerancia a fallas, mientras que la plataforma Linux reduce el juicio y aumenta el rendimiento al procesar referencias. Esto refleja vagamente los diferentes conceptos de desarrollo de Windows y Linux.
Finalmente, recuerde que las referencias no pueden ser nulas, y si puede haber objetos nulos, use punteros.
Enlace original: https://blog.csdn.net/luansxx/article/details/10134139