const Durcheinander in einer Klasse bzw. Deklaration



  • Danke wegen dieser umfassenden Übersicht !! Dabei würde ich gerne noch die Einsatzgebiete etwas abstecken, sonst setzt sich das nicht in meinen grauen Zellen :p

    • double const : ein unveränderliches double
    • const double : ist identisch mit double const ; hat man aus historischen Gründen zugelassen (ist leider die weitverbreitetste Form, obwohl sie eigentlich die "Ausnahme von der Regel" ist); das geht NUR, wenn vor const nichts mehr steht.

    Würde ich verwenden, wenn ich mathematische/physikalische Konstanten wie z.B. PI benötigen würde.

    • double const * : ein (veränderbarer) Zeiger auf ein (unveränderbares) double; Hier darf also der Zeiger woanders hinzeigen, aber das, wohin er zeigt, darf nicht verändert werden.
    • const double * identisch mit double const * ;

    Würde ich nun verwenden, wenn ich eine mathematische Funktion hätte, welche mehrere mathematischen/physikalischen Konstanten benötigt. Nun könnte ich mit einem Pointer die math./phy. Konstanten nutzen.

    • double * const : ein (unveränderbarer) Zeiger auf ein (veränderbares) double; Hier darf also der Zeiger NICHT woanders hinzeigen, aber das, wohin er zeigt, darf verändert werden.

    Würde ich nun verwenden, um in einem veränderbaren double Array, Hilfsklassen bzw. -funktionen zu definieren, welche stetig nur auf einen fest definierten Bereich anzuwenden sind.

    • double const * const : ein (unveränderbarer) Zeiger auf ein (unveränderbares) double

    Hmm... wenn ich den obengenannten Hilfsfunktionen auf eine math./phys. Konstante zu greifen müßte.

    • void f() const : eine konstante Memberfunktion; in dieser Funktion darf der Wert des Objektes zu dem sie gehört (="this"), nicht verändert werden.

    Würde ich nun etwas umformulieren in, eine konstante Memberfunktion dessen Rückgabewert, "welche bei einem Aufruf in einer anderen Routine", in diesem Aufruf nicht verändert werden darf. Stimmt das ?

    Kann jemand pauschal und aus dem Bauch heraus sagen, welche Routine schneller ist, ich meine Referenzen sind ja schonmal schneller, weil keine Kopie erstellt wird und wenn ich nun konstante Referenzen habe, könnte ich mir vorstellen, daß auch hier weniger Oerhead entsteht, also auch wieder schneller wird ?



  • CStoll schrieb:

    Undertaker schrieb:

    http://c2.com/cgi/wiki?AvoidConstCompletely
    http://c2.com/cgi/wiki?ConstIsaVirus
    😉

    Könntest du bitte deine unqualifizierten Bemerkungen sein lassen

    ich denke, es könnte hilfreich sein, wenn der OP 'const' auch aus diesem blickwinkel betrachtet.
    🙂



  • Zeiger auf konstante double's habe ich bisher eher selten verwendet, der Rest könnte hinkommen (wobei, anstelle eines konstanten Zeigers verwendet man in C++ oft Referenzen (und std::vector anstelle von Arrays)).

    Aber: const-Methoden (void f() const;) sind durchaus nützlich - wenn du irgendwo ein konstantes Objekt übergibst, wird sich der Compiler weigern, dessen "normale" Methoden zu verwenden:

    class test
    {
    public:
      void f1();
      void f2() const;
    };
    
    void test_fn(const test* param)
    {
      param->f1();//Fehler
      param->f2();//funktioniert
    }
    

    @Performance: const-Referenzen gegen Kopien haben den Geschwindigkeitsvorteil, weil nichts kopiert werden muß (kann bei umfangreichen Klassen teuer werden), bei allen anderen Konstellationen ist es eher eine Frage der Semantik, was "richtig" ist.



  • Hi Winn,

    noch eine kleine "Verständniserleichterung": "const" hat nichts mit "Konstante" zu tun, sondern ist eine "Schnittstellenzusage" !
    Wenn ich eine Variable als const deklariere, bedeutet das nicht automatisch, dass sich dahinter eine "Konstante" verbergen muss, sondern nur, dass ich verspreche, den Wert über diese Variable nicht zu verändern !

    Mal ein Beispiel (mit "Referenzen" statt Pointern, weil ich die lieber mag 😃 ):

    void f_const(int const& i) {
       cout << i; // operator<<(int const, ostream&) verändert i nicht)
    }
    
    void f_nonconst(int & i) {
       cout << ++i ; // operator++() verändert i
    }
    
    void f_beides(int const& i1, int& i2) {
       cout << i1 << ++i2;
       cout << i1 << i2;
    }  
    
    int main() {
       // einmal mit non-const-variable
       int i1 = 2;
       f_const(i1); // OK "obwohl i1 non-const"
       f_nonconst(i1); // OK; geht natürlich auch
    
       // einmal mit const-variable
       int const i2 = 3;
       f_const(i2); // OK
       f_nonconst(i2); // geht NICHT !! => Compiler-Error
    
       // einmal mit const-Referenz
       int const& i3 = i1; // OK: Ich sage nur: Über i3 will ich nicht verändern
    
       f_const(i3); // OK
       ++i1; // jetzt hat sich der Wert, auf den i3 verweist verändert - aber eben nicht über i3
       f_const(i3); // OK
       f_nonconst(i3); // => Compiler-Error
    
       // jetzt mal ein fieses Beispiel - dem geneigten Leser zum Selbstdurchdenken überlassen:
       f_beides(i1, i1);
    
       return 0;
    }
    

    Gruß,

    Simon2.



  • Undertaker schrieb:

    ...
    ich denke, es könnte hilfreich sein, wenn der OP 'const' auch aus diesem blickwinkel betrachtet.
    🙂

    So wie der eine Blinde den anderen führt ? Interessanter Ansatz... 😉



  • Simon2 schrieb:

    void f_beides(int const& i1, int& i2) {
       cout << i1 << ++i2;
       cout << i1 << i2;
    }  
    
    int main() {
    
       int i1 = 2;
       int const i2 = 3;
       int const& i3 = i1;
    
       f_beides(i1, i1);
       return 0;
    }
    

    Ich würde nun sagen, daß der Compiler meckert, i1 ist non-const und wird über das erste Argument der Funktion abgelehnt. Interessant würde es werden, wenn man "f_beides(i3,i1)" macht. Zur Runtime würde wahrscheinlich erst i1 auf 3 inkrementiert, anschliessend cout ausgeführt, also es würde "33" ausgegeben und danach auch wieder "33" ...



  • Nein, das compiliert anstandslos - du kannst eine nicht-konstante Variable problemlos an eine const-Referenz übergeben und du kannst genauso problemlos mehrere Referenzen auf die selbe Variable anlegen (und parallel verwenden). Allerdings trittst du dir damit selber auf die Füße, weil du nicht mehr vorhersagen kannst, was die erste Ausgabe-Anweisung liefern wird (++i2 liefert auf jeden Fall "3" zurück, aber ob das Inkrement durchgeführt wird, bevor oder nachdem i1 abgefragt wurde, liegt im Ermessen des Compilers).


  • Mod

    CStoll schrieb:

    Nein, das compiliert anstandslos - du kannst eine nicht-konstante Variable problemlos an eine const-Referenz übergeben und du kannst genauso problemlos mehrere Referenzen auf die selbe Variable anlegen (und parallel verwenden). Allerdings trittst du dir damit selber auf die Füße, weil du nicht mehr vorhersagen kannst, was die erste Ausgabe-Anweisung liefern wird (++i2 liefert auf jeden Fall "3" zurück, aber ob das Inkrement durchgeführt wird, bevor oder nachdem i1 abgefragt wurde, liegt im Ermessen des Compilers).

    "auf jeden Fall" ist eine gewagte Aussage. Das Ganze ist schlicht undefiniert und kann sich je nach Optimierungsstufe und Mondphase völlig anders verhalten - man denke z.B. an weitergehende Optimierungen durch inlining. Hier zu behaupten, der Compiler hätte hier nur eine bestimmte Wahlmöglichkeit, führt nur dazu, das Leute nur einmal ausprobieren, wie sich ihr Compiler verhält und dann ihren Code entsprechend schreiben.

    const als solches (hieß ursprünglich mal readonly, was weniger irreführend ist) ist eine Bedingung an den zu deklarierenden Bezeichner, nicht zwingend das Objekt, an dass dieser Bezeichner gebunden wird. Aus diesem Grunde ist es möglich, eine Referenz-auf-const an ein nicht-konstantes Objekt zu binden, denn dieses Const impliziert nur, dass das Objekt nicht mittels dieser Referenz verändert wird. Umgekehrt ist es nicht möglich, eine Referenz-auf-nicht-const an ein konstantes Objekt (oder ein Objekt, dass konstant erscheint, weil über eine Referenz-auf-const darauf verwiesen wird) zu binden.



  • Schön gesagt, camper
    (ich komme immer nicht auf Ausdrücke wie "Bezeichner" oder "gebunden an ...") 😃

    CStoll schrieb:

    Nein, das compiliert anstandslos ...Allerdings trittst du dir damit selber auf die Füße, weil du nicht mehr vorhersagen kannst, was die erste Ausgabe-Anweisung liefern wird ...

    CStoll schrieb:

    ...Das Ganze ist schlicht undefiniert ..

    Darauf wollte ich hinaus.

    Mir ist erst durch diesen Thread aufgefallen, wie leicht man hier einen blöden Fehler einbauen kann...
    (Obwohl meine Kollegin meinte:" Soo einfach kann es ja nicht sein, denn Dir ist das doch noch nie passiert, oder " 😉 )

    Gruß,

    Simon2.



  • Einen informativen Beitrag zur const-correctness hat auch Herb Sutter geliefert:
    http://www.gotw.ca/gotw/006.htm


Anmelden zum Antworten