2010-03-01 21 views
5

He probado el siguiente código:<< operador y recursividad

#include <iostream> 
using std::cout; 
using std::ostream; 

class X 
{ 
public: 
    friend ostream& operator<<(ostream &os, const X& obj) 
    { 
     cout << "hehe";   // comment this and infinite loop is gone 
     return (os << obj); 
    } 
}; 

int main() 
{ 
    X x; 
    cout << x; 
    return 0; 
} 

Cuando compilo & plazo esto, es como se esperaba; un bucle infinito Si elimino la declaración cout dentro de la función de amigo, la recursión no ocurre. ¿Por que es esto entonces?

+0

Estoy usando MinGW (GNU minimalista para Windows) por cierto. – legends2k

+1

¿Cómo observa que la recursión no ocurre? ¿Termina el programa correctamente? ¿O simplemente no imprime nada y tiene que terminarlo? (Tenga en cuenta que la recursividad de cola puede hacer que no reciba un desbordamiento de pila). –

+0

@litb: Inmediatamente cayó de nuevo a la terminal (no presioné una sola tecla para matar el proceso). – legends2k

Respuesta

7

El optimizador decide que toda la actividad restante no tiene ningún efecto y la optimiza. Si es correcto o incorrecto es un asunto diferente.

En particular:

X x; 

crea objeto vacío "x"

cout << x; 

llamadas:

return (os << obj); 

que está anexando objeto vacío; el compilador nota que 'os' no ha crecido desde la última llamada y no muestra ninguna promesa de hacerlo más (y nada más sucede) por lo que decide que todo el negocio es redundante y se puede truncar en este punto.

En caso de que llaman

cout << "hehe";   // comment this and infinite loop is gone 

hay alguna actividad extra para que el optimizador no elimina la siguiente llamada.

supongo que si ha inicializado x con cualquier cosa que no esté vacío, o después de realizar cualquier actividad que no sea nulo que no sea cout << "hehe";, tendría recursividad funcionamiento de la misma.

+0

En realidad, creo que el optimizador sería perfectamente correcto si el estándar especifica que la recursión infinita causa "comportamiento indefinido"; no hacer nada en absoluto estaría bien en ese caso. No puedo encontrar una copia del estándar de C++ en la red, ¿puede alguien que lo tenga verificar? –

+0

... en una nota no relacionada, me pregunto qué pasaría si la llamada estuviera encerrada en 'try-catch (...)' para capturar la excepción de desbordamiento de pila.Lo cual, creo, sería el comportamiento esperado, corrígeme si me equivoco. –

+1

No creo que esa excepción (que, dicho sea de paso, no es una excepción de C++, sino que es algún tipo de señal en * NIX y una excepción SEH en Windows) puede ser capturada. En realidad, no hay nada que puedas hacer cuando la pila se desborde: todo se ha vuelto loco. Si lo nota, las aplicaciones de Windows que se encuentran en desbordamiento de pila ni siquiera muestran un mensaje de error, porque no pueden hacer nada ahora que ya no hay más. –

6

En ambos casos (con y sin escribir "jeje") Visual Studio 2005 dicta la siguiente advertencia:

warning C4717: 'operator<<' : recursive on all control paths, function will cause runtime stack overflow 

En ambos casos se compila y en ambos casos se da un desbordamiento de pila.

Sin embargo, sin el "jeje", el desbordamiento de pila ocurre un poco antes.

+0

Tienes razón Patrick, gracias! Y gracias a Litb por dudar de la validez de mi conculsion que la recursión no sucede, lo que me hizo ejecutarlo a través de 'gdb' y ahora estoy satisfecho de ver un' SIGSEGV' que demuestra que en ambos casos ocurre una recursividad :) – legends2k

Cuestiones relacionadas