Exceptions filtern und weiterleiten



  • Tomahawk schrieb:

    } catch (const MyException& e) {
        // Forward the exception
        throw e;
      }
    

    Das ist besser als

    } catch (const MyException&) {
        // Forward the exception
        throw; // <-- ohne Objekt
      }
    

    geschrieben, sonst kriegst du Slicing-Probleme, wenn jemand von deiner Exceptionklasse erbt.


  • Mod

    seldon schrieb:

    Tomahawk schrieb:

    } catch (const MyException& e) {
        // Forward the exception
        throw e;
      }
    

    Das ist besser als

    } catch (const MyException&) {
        // Forward the exception
        throw; // <-- ohne Objekt
      }
    

    geschrieben, sonst kriegst du Slicing-Probleme, wenn jemand von deiner Exceptionklasse erbt.

    Da musste ich jetzt genau hinschauen. Beim Querlesen habe ich erst mal nur

    Code

    Das ist besser als

    Code

    gesehen.



  • Michael E. schrieb:

    Das const bei den Exceptions ist auch ziemlich überflüssig, weil Exceptions by value geworfen werden.

    Wenn man etwas const machen kann, ist das nie überflüssig.



  • TyRoXx schrieb:

    Wenn man etwas const machen kann, ist das nie überflüssig.

    Schreibst du das so?

    const int verdopple(const int i)
    {
        return 2 * i;
    }
    

    Und so?

    const int verdopple(const int* const i)
    {
        return 2 * (*i);
    }
    

    Edit: double ist kein toller Funktionsname.



  • Michael E. schrieb:

    TyRoXx schrieb:

    Wenn man etwas const machen kann, ist das nie überflüssig.

    Schreibst du das so?

    const int verdopple(const int i)
    {
        return 2 * i;
    }
    

    Und so?

    const int verdopple(const int* const i)
    {
        return 2 * (*i);
    }
    

    An so einen Schwachsinn habe ich bei der Behauptung natürlich nicht gedacht. Ich würde es falsch nennen, einen Rückgabewert const zu machen, nicht "überflüssig".
    Das bei den Argumenten kann man bei der Definition von mir aus machen. Warum sollte man die anders behandeln als andere lokale Variablen?
    Man macht die Parameter aber nicht const , damit die Parameterlisten bei Deklaration und Definition gleich sind (bzw. damit man die nicht jeweils anpassen muss).
    Wenn man einfach bei beidem const schreibt, steht in der Deklaration ein Implementationsdetail. Für den Benutzer der Funktion nutzlos und eher störend.



  • TyRoXx schrieb:

    ...

    Wieso falsch? Überflüssig trifft es viel besser:

    1. Wenn du Argumente by-value übergibst, machst du die Parameter nicht const , da es redundant wäre. Du kannst das Original sowieso nicht ändern, da du ja nur eine Kopie zur Verfügung hast.

    2. Wenn du einen fundamentalen Typen by-value zurückgibst, machst du den Rückgabetypen nicht const , da es redundant wäre, da der Rückgabewert per Definition ein rvalue ist. Einem rvalue kannst du eh nichts zuweisen.



  • TyRoXx schrieb:

    Warum sollte man die anders behandeln als andere lokale Variablen?

    Du lieferst im nächsten Satz selbst ein Argument: Was meinst du eigentlich mit "damit man die nicht jeweils anpassen muss"?



  • out schrieb:

    2. Wenn du einen fundamentalen Typen by-value zurückgibst, machst du den Rückgabetypen nicht const , da es redundant wäre, da der Rückgabewert per Definition ein rvalue ist. Einem rvalue kannst du eh nichts zuweisen.

    Laut C++11 ein prvalue. 🤡



  • out schrieb:

    1. Wenn du Argumente by-value übergibst, machst du die Parameter nicht const , da es redundant wäre. Du kannst das Original sowieso nicht ändern, da du ja nur eine Kopie zur Verfügung hast.

    Wieso? Ich nutze const wo ich kann. Und damit garantiert man dem Aufrufer und sich selbst, dass der Parameter im Verlauf der Funktion immer denselben Wert hat.



  • out schrieb:

    1. Wenn du Argumente by-value übergibst, machst du die Parameter nicht const , da es redundant wäre. Du kannst das Original sowieso nicht ändern, da du ja nur eine Kopie zur Verfügung hast.

    Aber die Kopie kann geändert werden.

    out schrieb:

    2. Wenn du einen fundamentalen Typen by-value zurückgibst, machst du den Rückgabetypen nicht const , da es redundant wäre, da der Rückgabewert per Definition ein rvalue ist. Einem rvalue kannst du eh nichts zuweisen.

    Man kann ihn aber als LValue binden und dann möchte man kein const . Wegen der Einheitlichkeit und weil es keinen positiven Effekt hat, schreibt man generell nicht const bei Rückgabewerten. Es ist sozusagen falsch.

    Michael E. schrieb:

    TyRoXx schrieb:

    Warum sollte man die anders behandeln als andere lokale Variablen?

    Du lieferst im nächsten Satz selbst ein Argument: Was meinst du eigentlich mit "damit man die nicht jeweils anpassen muss"?

    Deklaration: Kein const weil das ein Implementationsdetail ist und nicht zur Signatur gehört.
    Definition: const , weil sinnvoll.
    Man müsste also ständig darauf achten, const zu ergänzen oder zu entfernen. C++ ist aber schon Tipperei genug. Es ist damit nicht unnötig, sondern unpraktisch.

    Mal was zum Anfassen:

    //so soll das für den Benutzer aussehen
    int add(int a, int b);
    
    //ist länger ohne Mehrwert
    int add(int const a, int const b); 
    
    //const verhindert versehentliches Ändern
    int add(int const a, int const b)
    {
    	some_obscure_call(a); //wird a hier geändert? Ah, kann nicht wegen const.
    
    	for (int i = 0; i < a; ++a); //Tippfehler kompiliert nicht
    
    	return a + b;
    }
    

    Sone schrieb:

    out schrieb:

    1. Wenn du Argumente by-value übergibst, machst du die Parameter nicht const , da es redundant wäre. Du kannst das Original sowieso nicht ändern, da du ja nur eine Kopie zur Verfügung hast.

    Wieso? Ich nutze const wo ich kann. Und damit garantiert man dem Aufrufer und sich selbst, dass der Parameter im Verlauf der Funktion immer denselben Wert hat.

    Dem Aufrufer ist es egal, welche Werte die Kopie annimmt.



  • Sone schrieb:

    Laut C++11 ein prvalue.

    prvalues sind rvalues. Einfach mal die... du weisst schon.



  • Kellerautomat schrieb:

    Sone schrieb:

    Laut C++11 ein prvalue.

    prvalues sind rvalues.

    C++11 macht einen Unterschied zwischen prvalue und rvalue. Sonst würde man nicht zwei unterschiedliche Ausdrucksklassen daraus machen.

    Dass es hier irrelevant ist, dürfte mehr als offensichtlich sein 🤡



  • TyRoXx schrieb:

    Dem Aufrufer ist es egal, welche Werte die Kopie annimmt.

    Naja, ich dachte, wenn er nach Bugs in der Implementierung sucht... 😃



  • Mir gefaellt const in der Signatur deshalb nicht, weil es implementierungsdetails nach aussen traegt.

    Bestes Beispiel ist hier wohl strcpy:

    char* strcpy(char* trg, char const* src);
    

    das muesste ja wenn ich ueberall const schreibe wo ich const schreiben kann so lauten:

    char* const strcpy(char* const trg, char const* const src);
    

    Das const beim Returntyp ignorieren wir mal, weil das ein anderes Thema ist. Betrachten wir nun aber die Standard Implementierung von strcpy:

    while(*trg++=*src++)
      ;
    

    geht aber jetzt nicht mehr. Doof sowas. Wir muessen jetzt ploetzlich unnoetig kopieren.

    Es gibt einige Gruende warum ich den Parameter aendern will. Und in der Signatur erkennt man nun ob ich das tue. Sowas mag ich nicht.

    Prinzipiell ist const ueberall zu schreiben toll, wenn man dann aber inkonsistent werden muss, ists doof. Und ueberall Kopien ziehen will ich nicht.



  • Wieso ist es so ein "Problem", wenn du verrätst dass du innen den Zeiger veränderst? Klar, du willst Implementierungsdetails geheim halten. Aber das ist doch wirklich etwas übertrieben...



  • Sone schrieb:

    Wieso? Ich nutze const wo ich kann. Und damit garantiert man dem Aufrufer und sich selbst, dass der Parameter im Verlauf der Funktion immer denselben Wert hat.

    Du hast es nicht verstanden: Wenn du by-value machst, dann weiß der Aufrufer doch schon längst, dass sein Argument auch nach der Funktion noch denselben Wert hat, da das Argument ja kopiert wird, verstehst du?
    Wenn du als Entwickler sichergehen willst, dass der Parameter stets denselben Wert hat, machst du den Parameter trotzdem nicht const:

    1. Weil es den Aufrufer verwirrt. Er wundert sich, dass bei by-value der Paramter const ist und will wissen, was es damit auf sich hat.

    2. Du legst damit Implementierungsdetails frei. Dass ein Parameter in der Funktion nicht verändert werden darf, geht doch den Aufrufer nichts an. Das Offenlegen von Implementierungsdetails wird als schlechtes objektorientiertes Progammieren angesehen.

    Willst du also sichergehen, dass der Parameter stets denselben Wert hat, machst du das so:

    void fkt(int i)
    {
        const int& ci = i;
        // und erst jetzt beginnt die eigentliche Arbeit der Funktion.
    }
    


  • Sone schrieb:

    Wieso ist es so ein "Problem", wenn du verrätst dass du innen den Zeiger veränderst? Klar, du willst Implementierungsdetails geheim halten. Aber das ist doch wirklich etwas übertrieben...

    Weil es inkonsistent ist.

    Warum sind bei Funktion A die Parameter const und bei Funktion B nicht? Wenn du solche Sachen dann vor dir hast, ueberlegst du erstmal. Was macht B anders als A. Was vorallem dann lustig ist und dich auf vollkommen falsche Faehrten fuehrt, wenn du einen Bug suchst 😉

    Mal von dem Prinzip abgesehen, dass man Never Ever Ever Implementierungsdetails verraet.



  • out schrieb:

    Sone schrieb:

    Wieso? Ich nutze const wo ich kann. Und damit garantiert man dem Aufrufer und sich selbst, dass der Parameter im Verlauf der Funktion immer denselben Wert hat.

    Du hast es nicht verstanden: Wenn du by-value machst, dann weiß der Aufrufer doch schon längst, dass sein Argument auch nach der Funktion noch denselben Wert hat, da das Argument ja kopiert wird, verstehst du?

    Das habe ich schon lange kapiert, keine Sorge. Ich weiß, was by-value heißt 😉

    Wenn du als Entwickler sichergehen willst, dass der Parameter stets denselben Wert hat, machst du den Parameter trotzdem nicht const:

    1. Weil es den Aufrufer verwirrt. Er wundert sich, dass bei by-value der Paramter const ist und will wissen, was es damit auf sich hat.

    2. Du legst damit Implementierungsdetails frei. Dass ein Parameter in der Funktion nicht verändert werden darf, geht doch den Aufrufer nichts an. Das Offenlegen von Implementierungsdetails wird als schlechtes objektorientiertes Progammieren angesehen.

    Willst du also sichergehen, dass der Parameter stets denselben Wert hat, machst du das so:

    void fkt(int i)
    {
        const int& ci = i;
        // und erst jetzt beginnt die eigentliche Arbeit der Funktion.
    }
    

    Shade Of Mine schrieb:

    Mal von dem Prinzip abgesehen, dass man Never Ever Ever Implementierungsdetails verraet.

    Na bitte, sowas wollte ich hören.



  • Sone schrieb:

    C++11 macht einen Unterschied zwischen prvalue und rvalue. Sonst würde man nicht zwei unterschiedliche Ausdrucksklassen daraus machen.

    Dass es hier irrelevant ist, dürfte mehr als offensichtlich sein 🤡

    Ein rvalue ist entweder ein prvalue oder ein xvalue. Was an meiner Aussage jetzt falsch ist, darfst du mir also erklaeren.



  • Kellerautomat schrieb:

    Sone schrieb:

    C++11 macht einen Unterschied zwischen prvalue und rvalue. Sonst würde man nicht zwei unterschiedliche Ausdrucksklassen daraus machen.

    Dass es hier irrelevant ist, dürfte mehr als offensichtlich sein 🤡

    Ein rvalue ist entweder ein prvalue oder ein xvalue. Was an meiner Aussage jetzt falsch ist, darfst du mir also erklaeren.

    Gar nichts. Die hat keiner in Frage gestellt.


Anmelden zum Antworten