verlassen eines temporary scopes oder try blockes



  • Die Antwort auf die Frage "wie komme ich vorzeitig aus einem Block heraus?" ist "mit goto," was dir schon zu denken geben sollte. Mit ziemlich hoher Wahrscheinlichkeit ist das, was du da versuchst, Spaghetticode der schlimmsten Sorte.

    Wenn es dir nur um die Einrückung bei verschachtelten ifs geht: Ich benutze die Schreibweise

    if(foo) {
      ...
    } else if(bar) {
      ...
    } else if(baz) {
      ...
    } else if(qux) {
      ...
    } else {
      ...
    }
    


  • Meep Meep schrieb:

    da finde ich das dann so uebersichtlicher:

    int func()
    {
       temporary_scope
       {
          if(func1(...) == false)
          {
             ... code ...
             break;
          }
          if(func2(...) == false)
          {
             ... code ...
             break;
          }
          if(func3(...) == false)
          {
             ... code ...
             break;
          }
          ... usw
       }
       noch paar codezeilen
    }
    

    oder wie wuerdest du das ueber mehrere funktionen loesen ?

    Oh, jetzt erst den Code gesehen.
    Das geht trivial:

    int func()
    {
       func2();
       noch paar codezeilen
    }
    void func2() {
          if(func1(...) == false)
          {
             ... code ...
             return;
          }
          if(func2(...) == false)
          {
             ... code ...
             return;
          }
          if(func3(...) == false)
          {
             ... code ...
             return;
          }
          ... usw
       }
    }
    

    aber das kann ja nicht die frage gewesen sein, oder?



  • ja genau shade, darum gehts mehr oder weniger. ich wollte das mit der auslagerung nicht machen weil ich sonst echt viele parameter an die funktion mit uebergeben muss. wollte es halt in einer funktion lassen.

    Meep Meep



  • Meep Meep schrieb:

    ja genau shade, darum gehts mehr oder weniger. ich wollte das mit der auslagerung nicht machen weil ich sonst echt viele parameter an die funktion mit uebergeben muss. wollte es halt in einer funktion lassen.

    Viele Parameter sind wiederum ein Indiz, dass die Funktion zu viel machen könnte. Das sollte dich nicht abschrecken, aufzuteilen - im Gegenteil.

    Eventuell kann man ja einige Parameter zusammenfassen. Oder wenn das ganze einen Zustand hat, könntest du auch ein Klasse darum herum bauen, und Membervariablen abspeichern.

    < 💡 >



  • Meep Meep schrieb:

    ja genau shade, darum gehts mehr oder weniger. ich wollte das mit der auslagerung nicht machen weil ich sonst echt viele parameter an die funktion mit uebergeben muss. wollte es halt in einer funktion lassen.

    Ah, ok.
    Dann ists trivial. Die Lösung heißt: Exception.

    Wenn ein Fehler auftritt, wirf eine Exception. Dann sind die if-kaskaden automatisch weg.

    Das ganze lässt sicht, wenn du nicht unbedingt jede Funktion Kapseln willst, per macro (bzw. in c++ per varidic template mit perfect forwarding) lösen.

    Korrektes Kapseln wäre toll, geht aber nicht immer. Wir haben bei WinAPI Funktionen dann immer so ein macro verwendet:

    #define CHECKED(func) if(!(func)) throw SomeException(#func, GetLastError())
    

    und dann eben

    CHECKED(Something(a,b,c))
    CHECKED(Someother(d,a,f));
    ...
    

    und schon war alles schön mit exception versehen.



  • nun ja, wenn ein false zurueck gegeben wird ist es kein fehler. daher will ich eigendlich keine exceptions dafuer verwenden. die funktionen die ich da aufrufen muss werfen naemlich bei einem fehler ne exception. true false ist nur dafuer da, damit ich weiß das ich die naechste funktion auch noch aufrufen muss.
    wuerden sich da exception wirklich anbieten ?

    Meep Meep



  • Das kann man so nicht direkt beantworten. Wenn die Funktionen ein Socket erstellen und so weiter, dann wäre das durchaus ein Szenario, wo man eine Exception werfen könnte.

    Wenn Read fehlschlägt, weil die Verbindung getrennt wurde, dann ist das fast eine Glaubensfrage, ob man eine Exception wirft oder nicht. Je nach Anwendungsfall kann das eine oder andere (mehr) Sinn machen.

    Es ist aber definitiv einfacher folgendes zu schreiben:

    try
    {
     MyWinsockInitializer winsockInitializer; // Würde z.B. in der main() erfolgen
    
     MySocketClass socket;
    
     socket.Listen(2500);
    
     MySocketClass client;
    
     socket.accept(client);
    
     client.WriteLine("Hello!");
    
     std::cout << client.ReadLine() << std::endl;
    }
    catch (MySocketException& e)
    {
     std::cerr << e.what() << std::endl,
    }
    

    Anstatt

    MyWinsockInitializer winsockInitializer;
    
    if (winsockInitializer.Ready())
    {
     MySocketClass socket;
    
     bool error = false;
    
     if ((error = socket.Listen(2500)))
     {
      MySocketClass client;
    
      if ((error = socket.accept(client)))
      {
       if ((error = client.WriteLine("Hello!")) != 0)
       {
        std::string res = client.ReadLine();
    
        if ((error = client.GetState()) != MySocketClass::Disconnected)
         std::cout << client.ReadLine() << std::endl;
      }
     }
    }
    

    Setz deine Idee einfach mal um und poste das konkrete Ergebnis. So könnte man dir am besten helfen und so lernst du auch viel mehr, als wenn man irgendwelche Verallgemeinerungen schreibt...



  • Ich hab bei der Variable error einen Denkfehler drinne, aber geht ja ums Prinzip und zeigt gleich einen weiteren Schwachpunkt, wenn man die Rückgabewerte dauernd kontrollieren muss. Da wundert man sich dann, warum die nächste Funktion nicht das tut, was sie soll. Denn sie wird erst gar nicht aufgerufen 😃



  • Meep Meep schrieb:

    nun ja, wenn ein false zurueck gegeben wird ist es kein fehler. daher will ich eigendlich keine exceptions dafuer verwenden. die funktionen die ich da aufrufen muss werfen naemlich bei einem fehler ne exception. true false ist nur dafuer da, damit ich weiß das ich die naechste funktion auch noch aufrufen muss.

    Wieso musst du die naechste Funktion nicht aufrufen wenn eine Funktion false liefert?



  • Shade Of Mine schrieb:

    Meep Meep schrieb:

    nun ja, wenn ein false zurueck gegeben wird ist es kein fehler. daher will ich eigendlich keine exceptions dafuer verwenden. die funktionen die ich da aufrufen muss werfen naemlich bei einem fehler ne exception. true false ist nur dafuer da, damit ich weiß das ich die naechste funktion auch noch aufrufen muss.

    Wieso musst du die naechste Funktion nicht aufrufen wenn eine Funktion false liefert?

    weil wenn z.b. die 5te funktion ein eindeutiges ergebnis liefert, dann gibt sie false zurueck. true wenn ich die naechste funktion aufrufen muss.
    das ergebnis bekomm ich ueber die funktions-parameter zurueck. ist ein recht grosses struct.

    Meep Meep



  • Klingt irgendwie so als waere eine Schleife da recht praktisch.



  • jo ne schleife waere interessant: die funktionen haben aber nicht alle die selbe signatur. koennte man mit nem wrapper bestimmt bereinigen. ich denk mal das das alles zusammen zuviel aufwand wird.
    eigendlich gehts mir jetzt nicht mehr darum wie ich das jetzt schreibe. ich hab es ja so wie ich es brauche.
    es waere nur interessant fuer die zukunft, wenn mal wieder was aehnliches kommt, wie man an die sache richtig heran geht.
    der code im false-zweig ist leider auch nicht immer der selbe. sonst haette ich den schon mal ausgelagert.
    hab grad mal nachgezaehlt: hab 4 von 17 funktionen mit der selben signatur. der rest ist unterschiedlich.



  • Was gefällt dir denn nicht an meiner Variante?



  • cooky451 schrieb:

    Was gefällt dir denn nicht an meiner Variante?

    meinst du das ?

    cooky451 schrieb:

    Ich würde es so machen (wenn umstrukturieren wirklich nicht geht):

    bool b = true;
    
    b && b = f1();
    b && b = f2();
    b && b = f3();
    b && b = f4();
    // ...
    

    ehrlich gesagt versteh ich nicht inwiefern das hilfreich sein soll.

    Meep Meep



  • Es ist doch genau das, was du willst. Die Funktionen werden ausgeführt solange b true ist, ohne dass die Einrückungstiefe immer weiter steigt.



  • hola cooky

    nunja es ist zum teil das was ich moechte.
    ich habe ja ueberall noch eine abfrage fuer false dabei und die ist fast bei jeder funktion anders. was mich auch noch etwas stoert ist das die ueberpruefung fuer jede funktion durchgefuehrt wird, auch wenn ich bei der ersten urberpruefung schon ein false bekommen wuerde.

    Meep Meep



  • Meep Meep schrieb:

    was mich auch noch etwas stoert ist das die ueberpruefung fuer jede funktion durchgefuehrt wird, auch wenn ich bei der ersten urberpruefung schon ein false bekommen wuerde.

    Eben nicht. bei b && blah wird blah nicht mehr ausgewertet, wenn b schon false ist. (google: short circuit evaluation)



  • hab michwohl etwas bloed ausgedrueckt.

    Meep Meep schrieb:

    was mich auch noch etwas stoert ist das die ueberpruefung fuer jede funktion durchgefuehrt wird

    damit meinte ich das fuer jede funktion geprueft wird ob sie ausgefuert werden muss.

    bool b = true;
    
    b && b = f1();
    b && b = f2();
    b && b = f3();
    b && b = f4();
    

    wenn f1 false zurueck gibt, wird trotzdem noch 3 mal b geprueft. das meinte ich.

    Meep Meep


  • Mod

    Ohne vier Seiten Thread zu lesen (Entschuldigung, wenn ich ganz daneben liege):

    b = b && f1() && f2() && f3() && f4()
    


  • Meep Meep schrieb:

    wenn f1 false zurueck gibt, wird trotzdem noch 3 mal b geprueft. das meinte ich.

    Nicht zwangsläufig. Der Compiler kann sowas oft optimieren.

    Aber selbst wenn - wo wäre das Problem? b ist ein bool, und der liegt eh schon in einem register. Also kosten sind 0. Und würde mich nicht wundern wenn der Compiler das sogar wegoptimieren könnte.


Anmelden zum Antworten