Seite 1 von 1

Warum goto manchmal doch ganz nützlich ist ^^

Verfasst: Fr Apr 12, 2013 1:11 pm
von Xin
Genesys kann goto. Dafür gibt es einen Grund: Ich habe zwar keine Ahnung, wo man es brauchen müsste, aber ich weiß auch nicht alles und wenn jemand anderer zu dem Punkt kommt, dass er es braucht, wäre es doch gut, wenn es goto auch gibt.

Ich generiere derzeit C++-Quellcodes, ganz einfach, weil es schneller geht, ihn zu generieren, als ihn zu schreiben. Es geht also um viel Code, die erzeugte Headerdatei hat rund 1.8MB, die Cpp-Datei nochmal 435KB.
Eine Factory-Methode erhält dabei einen String und muss dafür eine von rund 650 Klassen erzeugen. Das folgende ist geschwindigkeitstechnisch nicht ideal, aber es wird sehr viel Code generiert und das erste Ziel ist, etwas zu erreichen, was funktioniert. Folgendes wird generiert:

Code: Alles auswählen

    if( false );
    else if( classname == Snafu::ClassName ) result = Snafu::Create( file );
    else if( classname == Foo::ClassName ) result = Foo::Create( file );
    else if( classname == Bar::ClassName ) result = Bar::Create( file );
    ...
Das ganze etwa 650 Mal.
Ergebnis: Compiler Error C1061: compiler limit : blocks nested too deeply.

Visual Studio erlaubt "nur" 128 Verschachtelungen. Erster Gedanke:

Code: Alles auswählen

    while( true )
    {
       if( classname == Snafu::ClassName ) { result = Snafu::Create( file ); break; }
       if( classname == Foo::ClassName ) { result = Foo::Create( file ); break; }
       if( classname == Bar::ClassName ) { result = Bar::Create( file ); break; }
       ...
       break;
    }
Müsste funktionieren, aber eine Schleife, um nachfolgende Abfragen zu verhindern?

Möglichkeit 2:
Eine Funktion, die was immer xxx::Create sofort mit return zurückspielt. Quasi eine zweite Factory-Funktion, die von der ersten Factory-Funktion aufgerufen wird, die dann die Nachbearbeitung macht.

Möglichkeit 3:

Code: Alles auswählen

     if( classname == Snafu::ClassName ) { result = Snafu::Create( file ); goto label; }
     if( classname == Foo::ClassName ) { result = Foo::Create( file ); goto label; }
     if( classname == Bar::ClassName ) { result = Bar::Create( file ); goto label; }

label:
Jetzt kompiliert es - nur streikt VC2010, weil ihm das Objektfile zu groß ist. Die Fehlermeldung liefert freundlicherweise aber gleich die Lösung: den Compilerswitch: "/bigobj". Es läuft zumindest :-)

Goto erschien mir hier die sinnvollste Lösung. Oder gibt es schönere Vorschläge?

Re: Warum goto manchmal doch ganz nützlich ist ^^

Verfasst: Fr Apr 12, 2013 7:38 pm
von nufan
Wie wärs das ganze über eine Map zu lösen? Einfach alle Factory-Methoden bzw. alle von einer abstrakten Factory-Klasse abgeleiteten Factorys in eine Map mit dem Klassennamen als Key packen. Je nach Klassenname die richtige Methode bzw. das richtige Objekt abfragen, dann ersparst du dir das if (du hast höchstens noch 1, ob die Map den Key überhaupt enthält).

Re: Warum goto manchmal doch ganz nützlich ist ^^

Verfasst: Sa Apr 13, 2013 12:14 pm
von Xin
dani93 hat geschrieben:Wie wärs das ganze über eine Map zu lösen?
Du wirst lachen, die Idee ist mir auch gekommen. Im Prinzip ist es ja auch nicht viel Arbeit, auf eine Map umzustellen, aber ich gebe zu, ich war zu faul. Es soll erstmal einfach nur funktionieren, an der Baustelle sind noch soviele andere Fallgruben und daher mache ich nichts komplizierter, als auch nur irgendwie nötig.
Beim Einlesen des Datenformates komme ich jetzt bis Zeile 2... bevor ich Zeile 1 optimiere, will ich wenigstens ein paar tausend Zeilen sicher einlesen können ;-)