Sinn von const bei Funktionen?



  • Hi, ich beschäftige mich gerade mit der korrekten Verwendung von const und lese dafür folgenden Artikel: http://www.cprogramming.com/tutorial/const_correctness.html
    Dort wird unter Anderem erwähnt, dass das Definieren von const-Funktionen nur bei Methoden Sinn macht, da hiermit der implizite this-Pointer const gesetzt wird.
    Aus reiner Neugier habe ich das einfach trotzdem mal bei "normalen" Funktionen ausprobiert.

    Folgender Code führt erwartungsgemäß zu einem Compilerfehler:

    int x = 5; // globale variable
    
    void foo() const {
      x = 3;
    }
    

    Folgender code hingegen wird problemlos übersetzt:

    int x = 5; // globale variable
    
    const void foo() {
      x = 3;
    }
    

    Das scheint aber keinen Sinn zu ergeben. Was genau ist denn hier nun const? Die globale Variable lässt sich ja problemlos ändern.



  • Stephan++ schrieb:

    Das scheint aber keinen Sinn zu ergeben.

    Der Schein trügt. Das void ist const, also nichts 😉



  • Mechanics schrieb:

    Stephan++ schrieb:

    Das scheint aber keinen Sinn zu ergeben.

    Der Schein trügt. Das void ist const, also nichts 😉

    Häääää? 😃
    Und welchen Sinn hätte dann folgendes Konstrukt?

    const int foo() {
      return 3;
    }
    

    Was bringt es mir, dass der int Rückgabewert const ist?



  • Das const bezieht sich auf den Rückgabewert. Wenn der Rückgabewert ein Zeiger ist, kann man mit diesem Zeiger das Objekt nicht verändern auf das der Zeiger zeigt. Bei int oder double macht const vor der Funktion aber keinen Sinn weil die Funktion ja nur eine Zahl zurückgibt die man sowieso nicht verändern kann. Bei void macht const auch keinen Sinn.



  • Ahh, ich glaube jetzt habe ich es Verstanden.

    Das folgende Konstrukt:

    int x = 5; // globale variable
    
    const int* foo() {
      return &x;
    }
    

    Hat den selben Effekt, als hätte ich einen const_cast auf x durchgeführt:

    void main(void) {
      int* x = foo(); // Fehler, weil x nicht const
      const int* xc = foo(); // Klappt, da xc const
    
    }
    

    Danke, nun bin ich etwas schlauer. 🙂


  • Mod

    const int foo() {
      return 3;
    }
    

    Ist tatsächlich effektiv equivalent zu

    int foo() {
      return 3;
    }
    

    denn jeder Funktionsaufruf würde durch §5.6 den Typ int haben. Der eigentliche Typ der Funktion ist natürlich im ersten Fall const int() , aber das macht nunmal keinen praktischen Unterschied.

    Falls der Rückgabetyp aber ein Klassentyp ist, macht es einen - wenn auch subtilen - Unterschied. Copy elision greift zwar, aber es kann nicht gemoved werden, falls sie nicht greift; I.e., ruft man

    const std::string f();
    

    auf, wird vom temporären Rückgabewert nicht gemoved, falls copy elision nicht angewandt wird. Von konstanten Objekten kann meistens nicht sinnvoll gemoved werden.



  • Stephan++ schrieb:

    Hat den selben Effekt, als hätte ich einen const_cast auf x durchgeführt

    Der const_cast ist nicht dazu da um const hinzuzufügen, sondern zu entfernen. Das hinzufügen von const passiert implizit:

    int* x;
    const int* xc = x; // Braucht keinen cast
    int* y = const_cast<int*>(xc); // Kann böse Fehler verursachen. Am besten nur benutzen wenn man weiß was man tut
    


  • sebi707 schrieb:

    Das hinzufügen von const passiert implizit:

    Ach, ist das so?
    http://ideone.com/TjXLqj


  • Mod

    Kellerautomat schrieb:

    sebi707 schrieb:

    Das hinzufügen von const passiert implizit:

    Ach, ist das so?
    http://ideone.com/TjXLqj

    Dass dieser Code nicht funktioniert hat einen guten Grund.

    §4.4/3 schrieb:

    [ Note: if a program could assign a pointer of type T** to a pointer of type const T** (that is, if line #1 below were allowed), a program could inadvertently modify a const object (as it is done on line #2). For example,

    int main() {
        const char c = ’c’;
        char* pc;
        const char** pcc = &pc; // #1: not allowed
        *pcc = &c;
        *pc = ’C’;              // #2: modifies a const object
    }
    

    end note ]



  • Kellerautomat schrieb:

    sebi707 schrieb:

    Das hinzufügen von const passiert implizit:

    Ach, ist das so?
    http://ideone.com/TjXLqj

    Das hat auch keiner behauptet, richtig wäre das so:

    int main()
    {
        int x = 42;
        int* p = &x;
        int* const* q;
        q = &p;
    }
    

    oder

    int main()
    {
        int x = 42;
        int* p = &x;
        const int** q;
        *q = p;
    }
    


  • Man will ja den int* in einen const int* convertieren und nicht einen int** in einen const int** (die Adresse die sich hinter const int** ist ja nicht Konstant, im Falle vom Kellerautomat, würde überhaupt nichts implizit konvertiert werden müssen) ansonsten kann man sich auch das merken, was im Draf steht.


Anmelden zum Antworten