2012-07-04 7 views
7

Duplicar posible:
Calling class method through NULL class pointer¿Por qué el método de llamada a través del puntero nulo "funciona" en C++?

#include <iostream> 
using namespace std; 
class test 
{ 
    int i; 
public: 
    test():i(0){ cout << "ctor called" << endl;} 
    void show() 
    { 
     cout<<"show fun called"<<endl; 
    } 
}; 

int main(int argc , char *argv[]) 
{ 
    test *ptr = NULL; 
    ptr->show(); 
    return 0; 
} 

claridad, se llamará sin ctor. ¿Es este estándar? ¿o solo alguna optimización del compilador ya que este puntero no se usa en la función de miembro show()?

+5

Desreferenciando un puntero nulo es UB. – chris

+2

Agregue 'i = 1;' dentro de 'show()' e intente ejecutarlo. –

+1

chris, UB significa hasta la implementación del compilador? y estoy usando g ++ 4.6.3. Jesse Good, por supuesto, falla seg, no hay duda. Me pregunto si el compilador generará código sin esto para la función miembro que no lo necesita. – bbc

Respuesta

22

El puntero no es necesario para llamar al método. El tipo del puntero es conocido, por lo que se conoce el código del método. El método no usa this, por lo que ejecuta el código muy bien. Es un comportamiento indefinido, pero es más eficiente no verificar si el puntero es NULL, por lo que se ejecuta.

+0

(¿Cómo afectaría un método virtual a su comportamiento observado? –

+2

Esperaría que fallara una llamada a método virtual, ya que necesita buscar el método en el vtable, que encontraría en el otro extremo del puntero, pero el puntero es NULL. –

+0

fallo de seg para virtual con g ++, no estoy seguro de que esto también dependa de la implementación. ¿El compilador generará vptr y vtblr sin objeto de clase? ¿Supongo que no por razones de eficiencia? – bbc

1

No es válido, el comportamiento no está definido y los resultados reales dependen de su compilador.

+0

Bueno, es válido. __esta función de llamada que no accede al puntero 'this' es solo una función estática. Simplemente agregue "estático": es lo mejor que puede hacer en el código que es estático por definición :) Y obliga a la función a usar __cdecl, por lo que no es necesario este puntero. Tenga en cuenta que agregar virtual hará una preparación más complicada que requiere desreferenciar el puntero, y luego segfault. –

-1

Bueno, antes que nada, no es válido ya que invoca un comportamiento indefinido. Realmente estás preguntando por qué el compilador lo permite, y la respuesta es porque ese es un código absurdo que simplemente no ocurrirá en una aplicación real, entonces, ¿para qué molestarse? El verdadero problema surge cuando el puntero se vuelve inválido en el tiempo de ejecución de una manera que no puede anticiparse mediante el análisis de código estático.

El compilador no está ahí para sostener su mano, está allí para compilar su código de acuerdo con la norma. Si ofrece advertencias útiles, entonces genial, pero no hay nada sintáctica o semánticamente ilegal allí, simplemente está escribiendo código que causa un comportamiento indefinido.

+0

gracias por el consejo. – bbc

8

Si mira el conjunto (para al menos un compilador), puede ver por qué se ejecuta (aunque es un comportamiento indefinido, como muchos han señalado). Por estas dos líneas:

test *ptr = NULL; 
ptr->show(); 

se genera Este conjunto (en un compilador Sólo traté):

00000004: C7 45 FC 00 00 00 mov   dword ptr [ebp-4],0 
      00 
0000000B: 8B 4D FC   mov   ecx,dword ptr [ebp-4] 
0000000E: E8 00 00 00 00  call  [email protected]@@QAEXXZ 

empuja el NULL (0) en la pila y llama al método ya que la dirección de el método es independiente de la instancia del objeto real.

Cuestiones relacionadas