GOTO in C++



  • Hallo,
    kann man nicht mit viel Liebe einfach setjmp/longjmp als böses-über-scope-grenzen-hinaus-goto betrachten?



  • Hallo zusammen, auch wenn dieses Topic wohl so langsam ausgesaugt ist....

    Kann mir jemand von Euch Oberprogrammierern einen Vorschlag machen wie man das Beispiel unten *ohne* goto besser hinkriegt?

    // die funktion do_check() soll "wahr" zurückgeben wenn der richtige
    // Wert gefunden wurde; dieser soll dann im String "command" wieder
    // zur verfügung stehen.
    
    bool
    do_check(string &command)
    {
        if(findfile(command))
                goto found;
    
        command.insert(0, "..\\");
        if(findfile(command))
                goto found;
    
        command.replace(0,3, "sub\\");
        if(findfile(command))
                goto found;
    
        command.insert(0, "..\\");
        if(findfile(command))
                goto found;
    
        return (false);
    
    found:
        command += ".frag";
        return (true);
    }
    


  • Hallo,

    warum nicht einfach alles in eine Bedingung? Ist das weniger übersichtlich?

    bool do_check(string &command)
    {
        if(findfile(command) 
           || findfile(command.insert(0, "..\\")) 
           || findfile(command.replace(0,3, "sub\\"))
           || findfile(command.insert(0, "..\\")))
        {
            command += ".frag";
            return true;
        }
        return false;       
    }
    

    Mir gefallen allerdings beide Varianten nicht sonderlich.



  • Dein Vorschlag ist interessant.
    Allerdings werden da immer alle vier varianten ausgewertet. Ich bin aber darauf angewiesen dass die varianten *genau* in der Reihenfolge abgearbeitet werden wie ich es vorgebe, und sobald die richtige Variante gefunden ist abgebrochen wird --> d.h. die anderen Varianten *nicht* mehr durchgearbeitet werden.

    Ich habe das gefühl das ist einer der Orte an dem goto durchaus seinen platz hat.



  • Allerdings werden da immer alle vier varianten ausgewertet

    Nein. Da irrst du dich. Die logischen Operatoren && und || haben in C++ eine short-circuit-Semantik. Ein oder-verknüpfter Ausdruck wird garantiert von links-nach-rechts ausgewertet. Sobald *ein* Ausdruck wahr ist, ist der ganze Ausdruck wahr und weitere Ausdrücke werden nicht mehr ausgewertet.
    Beim und ist das ähnlich. Auch hier wird von links-nach-rechts ausgewertet. Ist *ein* Ausdruck falsch, so wird der gesamte Ausdruck falsch.

    Das gilt aber *nur* für die built-in-Operatoren. Aus diesem Grund sollte man darauf verzichten die Operatoren || und && zu überladen.



  • Aha!
    Da habe ich jetzt aber allerdings etwas dazugelernt.
    Kannst Du mir das schriftlich geben dass das auf allen Implementationen so ist??? (ist das im Standard so festgeschrieben?)

    ich stelle mir dann immer noch die Frage: Was ist denn nun übersichtlicher?

    Du sagst das geht nur mit buit-in-operatoren: will heissen nur mit dem built-in-bool-typ? Das würde heissen wenn ich in der Bedingung einen selbsgebauten typ habe dann muss ich den wieder auf einen bool typ "umvergleichen" --> ich mache das ja im prinzip schon mit der findile() funktion.

    Noch was: eine relativ kleine änderung könnte auch dazu führen dass das mit der Bedingung wieder viel zu kompliziert wird:

    bool
    do_check(string &command)
    {
        if(findfile(command))
                goto found;
    
        command.insert(0, "..\\");
        if(findfile(command))
                goto found;
    
        command.replace(0,3, "sub\\");
        if(findfile(command))
        {
                command += ".exe";
                goto found;
        }
    
        command.insert(0, "..\\");
        if(findfile(command))
                goto found;
    
        return (false);
    
    found:
        command += ".frag";
        return (true);
    }
    

    [ Dieser Beitrag wurde am 12.06.2003 um 21:07 Uhr von HumeSikkins editiert. ]



  • ooops... ich glaube ich sollte mich anmelden damit ich meine falsch getippten Einträge auch editieren kann...



  • Kannst Du mir das schriftlich geben dass das auf allen Implementationen so ist??? (ist das im Standard so festgeschrieben?)

    Sicher. In Kapitel 5.14 (logical AND operator) und 5.15 (logical OR operator) steht es schwarz auf weiß.

    Was ist denn nun übersichtlicher?

    Das ist wohl eine Geschmacksache. Ich persönlich würde meine Variante bevorzugen, da die Reaktion dort unmittelbarer auf den Test folgt.

    Du sagst das geht nur mit buit-in-operatoren: will heissen nur mit dem built-in-bool-typ? Das würde heissen wenn ich in der Bedingung einen selbsgebauten typ habe dann muss ich den wieder auf einen bool typ "umvergleichen" --> ich mache das ja im prinzip schon mit der findile() funktion.

    Es geht mit jedem Typ der sich implizit nach bool konvertieren lässt. Also auch mit udts die einen Operator bool, operator void* (oder einen beliebigen anderen nach-Zeiger-Umwandlungsop) oder operator! besitzen.

    Problematisch wird's für udts die den operator&& oder operator|| überladen (sowas wirst du eher selten finden).

    Also:

    class Foo
    {
    public:
    bool operator&& (const Foo& rhs)
    {
    return true;
    }
    };
    
    Foo func();
    
    int main()
    {
        if (func() && func())
            bla;
    }
    

    Hier wird func auf jeden Fall zweimal func aufgerufen.

    Hier hingegen:

    class Foo
    {
    public:
    operator void* () 
    {
        return 0;
    }
    };
    
    Foo func();
    
    int main()
    {
        if (func() && func())
           true;
    }
    

    wird func() *garantiert* nur einmal aufgerufen.

    Noch was: eine relativ kleine änderung könnte auch dazu führen dass das mit der Bedingung wieder viel zu kompliziert wird:

    Ich denke das Problem bei dieser Funktion ist nicht mehr goto-ja-nein sondern vielmehr die Funktion an sich.
    Die Funktion hat imo schlicht und einfach zuviele verschiedene Aufgaben hat. Sie prüft *und* fügt ein suffix hinzu. Das macht das ganze zu kompliziert. Und mit der Zeit wird eher noch der ein oder andere Spezialfall hinzukommen.
    Ich würde das ganze viel eher in einzelne kleine Funktionen aufteilen.



  • Ja, Du hast recht. (bei mir stehts allerdings in Kapitel 6.2.2 (TC++PL third edtition)) Ich hatte allerdings den folgenden Satz im Kopf, den du im gleichen Kapitel findest:

    The order of evaluation of subexpressions within an expression is undefined. In partucular, you cannot assume that the expression is evaluated left to right. For example: ...

    Du magst recht haben damit dass die Funktion selbst schlecht aufgebaut ist. Das ganze scheint auch vielleicht ein wenig an den Haaren herbeigezogen, da das Beispiel nur "ungefähr" einem "real-world" example entspricht.

    mit switch haben wir die möglichkeit den programmfluss so zu konstruieren:

    ¦
      o---\--\--\
      ¦   ¦  ¦  ¦
      ¦<--/  ¦  ¦
      ¦      ¦  ¦
      ¦<-----/  ¦
      ¦         ¦
      ¦<--------/
      V
    

    hingegen haben wir für das folgende nur die möglichkeit einen manchmal etwas komplizierten if else konstrukt oder mit goto (mit return kannst Du etwas ähnliches erreichen, bist dann aber direkt aus der Funktion raus):

    ¦
      o---------\
      ¦         ¦
      o------\  ¦
      ¦      ¦  ¦
      o---\  ¦  ¦
      ¦   ¦  ¦  ¦
      ¦<--/--/--/
      V
    

    Ich möchte damit eigentlich nur sagen dass es durchaus "sensible uses" für goto gibt. Auch wenn der resultierende code nicht unbedingt "clean" aussieht. Es kann sein dass der gleiche Code, ohne goto wesentlich komplizierter wird.



  • Ja, Du hast recht. (bei mir stehts allerdings in Kapitel 6.2.2 (TC++PL third edtition))

    Die Kapitelangaben bezogen sich auf den International Standard ISO/IEC 14882. Also den C++ Standard.

    Einen Final Draft findest du hier: http://www.kuzbass.ru/docs/isocpp/

    In diesem Fall passen sogar die Kapitelangaben (also 5.14 und 5.15)

    Ich möchte damit eigentlich nur sagen dass es durchaus "sensible uses" für goto gibt.

    Bezweifle ich gar nicht.


Anmelden zum Antworten