Tut zu viel "const" noch gut?



  • quadratschädel schrieb:

    für den aufrufer, für den programmierer der funktion aber nicht. er will einen parameter in der funktion vllt. wirklich unveränderbar haben.

    dann kann man das ja gerne wenn man so verrueckt ist in der implementierung auch so machen (wobei es halt sinnlos ist und nur die lesbarkeit des codes reduziert) aber bitte NIE NIE NIE in einer interface definition. Denn das erschwert nur das verstehen und lesen.

    und bringen tut es ja absolut garnichts...



  • Blaze schrieb:

    Jeder empfiehlt das SChlüsselwort const so oft wie möglich zu benutzen.

    Mich würde echt mal interessieren, wer so etwas empfiehlt. Jeder bestimmt nicht... 🙄



  • Moin.

    Steht in manchen Büchern.
    Mal ne Frage, wie soll man das bitte trennen? Entweder der Parameter ist const
    oder nicht. Und das sollte in der Deklaration sowie in der Definition gleich
    sein, wegen unseren beliebten Compilern.



  • void f(int a); // const macht beim Parameter keinen Sinn, ist eine Kopie
    void f(const int& a); // macht Sinn, da Referenz
    void f(const MyClass a); // kann Sinn machen, je nach Aufbau der Klasse bzw wie der Copy-
                             // konstruktor gestaltet wurde. Gutes Design? Naja...
    

  • Mod

    void f(const int a);     // const wird vom Compiler ignorierert, der Funktionstyp ist void(int)
                             // Funktion kann beliebig mit oder ohne const redeklariert werden
                             // Nur im Falle einer Definition wird ein evtl. vorhandenes const innerhalb der Definition beachtet
    void f(const int& a);    // Referenzen sind selbst nie const-qualifiziert (es sind keine Objekte), hier wäre ein const vor a nicht zulässig
                             // const vor dem int ist natürlich eine ganz andere Geschichte
                             // Funktionstyp ist void(const int&)
    void f(const MyClass a); // const wird vom Compiler ignorierert, der Funktionstyp ist void(MyClass)
                             // Funktion kann beliebig mit oder ohne const redeklariert werden
                             // Nur im Falle einer Definition wird ein evtl. vorhandenes const innerhalb der Definition beachtet
    // Merke: eine Top-Level cv-Qualifikation eines Funktionsparameters beeinflusst den Funktionstyp nicht
    
    const void g();          // const wird vom Compiler beachtet und muss bei Redeklaration erneut dastehen
                             // Funktionstyp ist const void()
                             // aber: Typ des Funktionsaufrufs g()  ist void !
                             // Deshalb: dieses const nicht verwenden, da bedeutungslos
    const int g();           // analog zu const void g(), Typ des Funktionsaufrufs g()  ist int, da skalar
    struct Foo { int x; };
    const struct Foo g();    // const wird vom Compiler beachtet und muss bei Redeklaration erneut dastehen
                             // Funktionstyp ist const Foo()
                             // Typ des Funktionsaufrufs g() ist
                             // in C: Foo
                             // in C++: const Foo
    


  • Nexus schrieb:

    Blaze schrieb:

    Jeder empfiehlt das SChlüsselwort const so oft wie möglich zu benutzen.

    Mich würde echt mal interessieren, wer so etwas empfiehlt. Jeder bestimmt nicht... 🙄

    Und wenn steht diese Empfehlung wohl immer im Zusammenhang mit sinnvoller const-Behandlung (Thema const-correctness). Ich gehöre auch zu der Fraktion, die const überall wo möglich und sinnvoll einbaut. Und nein, die Lesbarkeit leidet bei entsprechender Formatierung nicht darunter.

    Das Codebeispiel vom OP ist mehr als grausam (von den fehlerhalften const-Verwendungen mal abgesehen).
    a) Trennt man ohnehin im Regelfall Definition von Deklaration
    b) Muss man nicht alles zwangsweise in eine Zeile quetschen

    Daher: Unabhängig von const oder nicht const, kann Code lesbar bleiben. Und const-correctness macht auch Sinn - sofern man diese sinnvoll anwendet.

    cu André



  • asc schrieb:

    Ich gehöre auch zu der Fraktion, die const überall wo möglich und sinnvoll einbaut.

    Das ist ja auch gut so. Mich hat es nur stutzig gemacht, wenn behauptet wird, const sollte man überall einsetzen, wo es möglich ist.

    Wann ist eigentlich ein const -Rückgabetyp bei eigenen Typen von Bedeutung? Mir fällt gerade nur das folgende Beispiel (und ähnliche) ein:

    struct Vec2D
    {
    	int x;
    	int y;
    	Vec2D(int nx, int ny) : x(nx), y(ny) {}
    };
    
    /*const*/ Vec2D operator+ (const Vec2D& Left, const Vec2D& Right)
    {
    	return Vec2D(Left.x + Right.x, Left.y + Right.y);
    }
    
    int main() 
    {
    	Vec2D A(3, 4), B(7, -2);
    
    	(A + B) = Vec2D(8, 0); // geht nicht, wenn op+ const-Rückgabetyp
    }
    

  • Administrator

    Nexus schrieb:

    Wann ist eigentlich ein const -Rückgabetyp bei eigenen Typen von Bedeutung?

    Zum Beispiel für sowas:

    class Test
    {
    private:
      std::string m_name;
    
    public:
      std::string const& get_name() const;
    }
    

    Damit erspart man sich eine Kopie und erst recht, wenn man nur lesen möchte und nicht schreiben. Das kann der Compiler dann auch extrem optimieren.
    Und das gilt natürlich nicht nur für std::string , sondern für jedes grössere Objekt.

    Grüssli



  • Ja, Const-Referenzen sind mir schon klar 😉

    Ich hab mich wohl zu wenig genau ausgedrückt. Ich dachte eher an einen Rückgabetypen wie const MyClass (also keine Referenz); also wo das noch eine Anwendung findet...



  • Nexus schrieb:

    Wann ist eigentlich ein const -Rückgabetyp bei eigenen Typen von Bedeutung?

    Const bei eigenen Rückgabetypen sind genau aus den Gründen sinnvoll die du schon als Beispiel heranziehst:

    Nexus schrieb:

    int main() 
    {
    	Vec2D A(3, 4), B(7, -2);
    	
    	(A + B) = Vec2D(8, 0); // geht nicht, wenn op+ const-Rückgabetyp
    }
    

    Und um ein weiteres Beispiel von Scott Meyers (Effektiv C++ Programmieren, 3te Auflage; Tipp 3; Seite 35) zu bringen: Es macht auch sinn um bestimmte weitere Fehlerfälle zu verhindern:

    if(a * b = c) // Ausversehen = statt ==
    

    Gut, je nach Warnungseinstellungen sollte dies eh angemeckert werden, aber dies ist ja nur eines von vielen Beispielen.



  • asc schrieb:

    if(a * b = c) // Ausversehen = statt ==
    

    Gut, je nach Warnungseinstellungen sollte dies eh angemeckert werden, aber dies ist ja nur eines von vielen Beispielen.

    Müsste a*b nicht eh eine temporäre Variable liefern die nicht als lvalue fungieren kann? Sprich: sollte der sich der Compiler da nicht weigern, egal ob op* const liefert oder nicht?


  • Mod

    pumuckl schrieb:

    Müsste a*b nicht eh eine temporäre Variable liefern die nicht als lvalue fungieren kann? Sprich: sollte der sich der Compiler da nicht weigern, egal ob op* const liefert oder nicht?

    Der Ausdruck a*b ist (wenn es sich nicht gerade um einen überladenen Operator mit Referenzrückgabe handelt) ein rvalue. Ist der Typ des Ausdrucks der einer Klasse, verweist er zudem auf ein Objekt, nämlich ein temporäres.
    Ist der linke Operand des = Operators ein Klassenobjekt, wird der Scope der Klasse nach Überladungen durchsucht (und wenigstens eine wird immer gefunden werden). Überladungen des Zuweisungsoperators sind stets nicht-statische Memberfunktionen. Das Argument des Objektparameters einer nichtstatischen Memberfunktion kann sowohl ein lvalue als auch ein rvalue sein.

    std::bitset<10> x;
    x[8] = true;
    

    Das Ergebnis von x[8] ist hier ein temporäres Objekt des Typs std::bitset<10>::reference - und diese Zuweisung ist zweifellos nicht sinnlos.


Anmelden zum Antworten