2009-07-18 23 views
6

¿Podría alguien explicarme por qué este código solo imprime "42" en lugar de "created \ n42"?¿Por qué este código solo imprime 42?

#include <iostream> 
#include <string> 
#include <memory> 

using namespace std; 

class MyClass 
{ 
public: 
    MyClass() {cout<<"created"<<endl;}; 
    int solution() {return 42;} 
    virtual ~MyClass() {}; 
}; 

int main(int argc, char *argv[]) 
{ 
    auto_ptr<MyClass> ptr; 
    cout<<ptr->solution()<<endl; 
    return 0; 
} 

Por cierto yo probamos este código con diferentes valores en solución y siempre me dan el valor "correcto", por lo que no parece ser un valor aleatorio suerte.

+13

Mi consejo sería consultar la "Guía del autoestopista galáctico". – NoMoreZealots

Respuesta

27

Porque muestra un comportamiento indefinido: desreferencia un puntero nulo.

Cuando dicen:

auto_ptr<MyClass> ptr; 

se crea un autopointer la que no apunta a nada. Esto es equivalente a decir:

MyClass * ptr = NULL; 

Entonces, cuando usted dice:

cout<<ptr->solution()<<endl; 
que

eliminar la referencia de este puntero nulo. Hacer eso no está definido en C++: para su implementación, parece funcionar.

+1

Esa fue una operación interesante de respuesta aceptada, jaja. : P – GManNickG

+0

Pero el mío fue primero :-) –

+0

Oh, no me estoy quejando :) Subí el tuyo después de enviarlo, fui lento en el sorteo. – GManNickG

2

Debido a que usted no conoce la pregunta a la respuesta xD

Parece que no está llamando al constructor, ¿verdad?

+0

Eso es lo que estaba pensando ... – CalebHC

21

std::auto_ptr no creará automáticamente un objeto para usted. Es decir, ptr en main como está se inicializa a null. Desreferenciar esto es un comportamiento indefinido, y por casualidad tienes suerte y obtienes 42 como resultado.

Si realmente crear el objeto:

int main(int argc, char *argv[]) 
{ 
    auto_ptr<MyClass> ptr(new MyClass); 

    cout << ptr->solution() << endl; 

    return 0; 
} 

Usted obtendrá la salida esperada.

+3

Siempre supe que 42 era la respuesta a todo, pero nunca pensé que ese puntero nulo también lo supiera. ¡Gracias! ¿Por qué esto no arroja un error de segmentación? – rlazo

+2

Porque eso es lo que hace el comportamiento indefinido, podría parecer que funciona, o podría reformatear su computadora. Probablemente la razón por la que funcionó es porque en realidad no operabas con miembros de la clase. El compilador ve que estás accediendo a 'MyClass :: solution'. Pone 0 para el puntero 'this', porque eso es lo que es, va a la función, obtiene 42 como resultado y regresa. Dale a tus clsas un miembro privado 'int answer', ponlo a 42 en el constructor, y devuelve eso en' solution() 'y deberías ver un crash, porque ahora estás tratando de usar el puntero' this' nulo . – GManNickG

+1

@rlazo: no arroja un segfault porque su función de solución no tiene acceso a ninguna variable miembro, por lo que el puntero "this" no se usa dentro de la función. –

2

No está creando una instancia del objeto.
Usted solo está creando un puntero inteligente.

Cuando llama al método, está desreferenciando un puntero NULL, por lo que como mencionó Neil, ahora tiene un comportamiento indefinido. Pero como su código no intenta acceder a ninguna variable miembro afortunadamente no falla.

Prueba esto:

auto_ptr<MyClass> ptr(new MyClass); 
+0

Diría "desafortunadamente" en lugar de "afortunadamente". –

1

Debido ptr es inicializado y un poco de suerte. Primero debe llamar a new para ello:

auto_ptr<MyClass> ptr(new MyClass); 
1

usted no está consiguiendo un accidente debido a que el método de la "solución" no tiene que utilizar realmente los miembros de la clase. Si devolvieras un miembro o algo así, probablemente obtendrías un colapso.

3

En primer lugar, tenga en cuenta que el operador -> de auto_ptr esencialmente se reenvía al puntero contenido.Así que para esta discusión, el código en main hace equivalente a:

MyClass* ptr = NULL; 
cout << ptr->solution() << endl; 

A continuación, tenga en cuenta que los compiladores tienden a poner en práctica las funciones miembro de una manera que actúan muchísimo funciones que no son miembros como si fueran la this puntero pasado como otro argumento de función. Por lo tanto, desde el punto de vista de su compilador actual, su código en main actúa como si fuera:

MyClass* ptr = NULL; 
cout << solution(ptr) << endl; 

con solución escribirse como:

int solution(MyClass* this) { return 42; } 

En este caso se hace evidente por qué no había una choque.


Sin embargo como ya se ha mencionado, estos son detalles internos de cómo poner en práctica los compiladores de C++, que no están especificados por el estándar del lenguaje. Entonces, en teoría, este código podría funcionar como se describe aquí en un compilador, pero fallar o hacer algo completamente diferente en otro compilador.

Pero en la práctica, incluso si el estándar no garantiza este comportamiento, cualquier compilador particular podría garantizarlo si así lo desean. Por ejemplo: dado que MFC se basa en este comportamiento, es muy poco probable que Visual Studio deje de admitirlo alguna vez. Por supuesto, tendrías que investigar cada compilador particular donde tu código podría ser usado para asegurarte de que realmente garantizan este comportamiento.

Cuestiones relacionadas