2010-03-01 20 views
5

ich den folgenden Code versucht:Überlastung Operator << und Rekursion

#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; 
} 

Als ich & laufen diese kompilieren, ist es wie erwartet; eine Endlosschleife. Wenn ich die cout Anweisung innerhalb der Friend-Funktion entferne, tritt die Rekursion nicht auf. Wieso ist es so?

+0

Bin mit MinGW (Minimalist GNU für Windows) BTW. – legends2k

+1

Wie bemerken Sie, dass die Rekursion nicht stattfindet? Beendet es das Programm richtig? Oder druckt es einfach nichts und du musst es beenden? (Beachten Sie, dass die Tail-Rekursion dazu führen kann, dass Sie keinen Stack-Überlauf erhalten). –

+0

@litb: Es fiel sofort auf das Terminal (ich habe keine einzige Taste gedrückt, um den Prozess zu beenden). – legends2k

Antwort

7

Optimizer entscheidet, dass alle Ihre verbleibenden Aktivitäten keine Auswirkungen haben und optimiert sie. Ob es richtig oder falsch ist, ist eine andere Sache.

Insbesondere:

X x; 

schafft leeres Objekt "x"

cout << x; 

Anrufe:

return (os << obj); 

die leer Objekt anhängt; Der Compiler bemerkt, dass "os" seit dem letzten Aufruf nicht gewachsen ist und keine weiteren Versprechen mehr gibt (und nichts anderes passiert), so dass es entscheidet, dass das ganze Geschäft überflüssig ist und an dieser Stelle abgeschnitten werden kann.

Im Fall rufen Sie

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

gibt es einige zusätzliche Aktivität so der Optimierer nicht den folgenden Aufruf nicht entfernt.

Ich denke, wenn Sie x mit etwas nicht-leer initialisiert haben, oder eine andere als Null-Aktivität als cout << "hehe"; durchgeführt, würden Sie Rekursion genau das gleiche ausführen.

+0

Eigentlich denke ich, dass der Optimierer vollkommen richtig wäre, wenn der Standard angibt, dass unendliche Rekursion "undefiniertes Verhalten" verursacht; in diesem Fall wäre nichts in Ordnung. Ich kann keine Kopie des C++ - Standards im Internet finden, kann jemand, der es überprüft haben? –

+0

... auf nicht verwandten Hinweis, ich frage mich, was passiert, wenn der Aufruf in 'try-catch (...)' eingeschlossen wurde, um Stapelüberlauf Ausnahme zu erfassen.Was, denke ich, wäre das erwartete Verhalten, korrigiere mich, wenn ich falsch liege. –

+1

Ich glaube nicht, dass eine solche Ausnahme (die übrigens keine C++ - Ausnahme ist, sondern irgendeine Art von Signal auf * NIX und eine SEH-Ausnahme unter Windows) gefangen werden kann. Eigentlich kann man nichts machen, wenn der Stapel überläuft: Alles ist schon verrückt geworden. Wenn Sie bemerken, dass Windows-Anwendungen, die in den Stack-Überlauf geraten, nicht einmal eine Fehlermeldung anzeigen, weil sie jetzt nichts mehr tun können, weil es keinen Stack mehr gibt. –

6

In beiden Fällen (mit und ohne „hehe“ schreiben) Visual Studio 2005 gibt die folgende Warnung:

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

In beiden Fällen ist es kompiliert und in beiden Fällen gibt es einen Stapelüberlauf.

Ohne den "hehe" tritt der Stapelüberlauf jedoch etwas früher auf.

+0

Du hast Recht Patrick, danke! Und dank litb, dass ich an der Richtigkeit meiner Vermutung zweifle, dass Rekursion nicht stattfindet, was mich dazu brachte, über 'gdb' zu laufen, und jetzt bin ich zufrieden, ein' SIGSEGV' zu sehen, was beweist, dass in beiden Fällen eine Rekursion auftritt :) – legends2k