Warum sind rvalues von nicht-builtin-Typen nicht automatisch const?



  • knivil schrieb:

    wxSkip schrieb:

    1. Weil rvalues von builtin-Typen sich const verhalten. D.h.:

    Die 5 in deinem Beispiel ist kein L-Value, da kein Speicher mit ihr assoziiert ist.

    Das gilt nicht. Ich hätte genausogut return int(5); schreiben können, was sozusagen ein (inline-)Konstruktoraufruf und damit eine Speicherassoziierung ist, aber trotzdem nicht funktioniert.

    @camper: Wenn ich lvalues und rvalues noch nicht verstanden habe (in der Tat verstehe ich die rvalue-Referenzen und das move-Zeug auch noch nicht so gut), hast du dann auch einen Link dazu?

    Shade Of Mine schrieb:

    verbieten ist immer doof. erlauben ist immer toll.

    Das hätte ich jetzt nicht von einem erfahrenen Programmierer erwartet. ⚠

    Wenn ihr wissen wollt, wie ich draufgekommen bin: http://gotw.ca/gotw/006.htm (und auch bei Effective C++): möglichst alle nicht-builtin-Rückgabewerte const machen. (geht außerdem bei einem Konstruktor ja nicht)



  • Das hätte ich jetzt nicht von einem erfahrenen Programmierer erwartet.

    Sind wir jetzt im Kindergarten?



  • knivil schrieb:

    Das hätte ich jetzt nicht von einem erfahrenen Programmierer erwartet.

    Sind wir jetzt im Kindergarten?

    😃 Nein.
    Aber grundsätzlich Compiler-Restriktionen abzulehnen finde ich ... naja.


  • Mod

    wxSkip schrieb:

    Ich hätte genausogut return int(5); schreiben können, was sozusagen ein (inline-)Konstruktoraufruf und damit eine Speicherassoziierung ist, aber trotzdem nicht funktioniert.

    Nur Klassen verfügen über Konstruktoren. int(5) ist kein Konstruktoraufruf und erzeugt auch kein Objekt, nicht mal ein Pseudo-objekte.
    Skalare Typen haben eine wichtige Eigenschaft: Die eingebauten Operatoren können unmittelbar mit Werten (d.h. Objektrepräsentationen a.k.a. Bitmuster) dieser Typen umgehen. Im Ausdruck

    5+5
    

    ist kein Objekt im Spiel. Die Klassifizierung in l- und r-values wurde ja gerade deshalb eingeführt, um diesen Unterschied zwischen Objekten und Werten formal zu erklären

    42 = 42; // (1)
    const int foo = 0;
    foo = 42; // (2)
    

    Beide Zuweisungen sind fehlerhaft, und in beiden Fällen könnte man sagen, dass die linke Seite "konstant" ist. Die Natur dieser Konstanz ist aber völlig verschieden.

    Für Klassen und Arrays gilt das nicht: es ist in C++ unmöglich, auf den Wert eine Klasse auf eine Wesie zu verweisen, wie es (1) tut. Der Zustand von Klassen existiert niemals losgelöst von einem konkreten Objekt (Array-rvalues sind sowieso exostische Kreaturen, die nur über Klassen-rvalues erzeugt werden können). Du müsstest also das Objektmodel von C++ erheblich verändern, um hier eine Angleichung an skalare Typen zu erreichen.
    Ist dein Konstanz dagegen im Sinne von const-qualifiziert zu verstehen, dann ist das auch nur willkürlich: skalare rvalues sind niemals cv-qualifiziert, eben weil es keine Objekte sind.

    wxSkip schrieb:

    Wenn ihr wissen wollt, wie ich draufgekommen bin: http://gotw.ca/gotw/006.htm (und auch bei Effective C++): möglichst alle nicht-builtin-Rückgabewerte const machen. (geht außerdem bei einem Konstruktor ja nicht)

    Ja. Hier schiesst Sutter übers Ziel hinaus.



  • Shade Of Mine schrieb:

    verbieten ist immer doof. erlauben ist immer toll.

    Ja, diese ganzen Verbote durch Const-Correctness sind schlimm.



  • wxSkip schrieb:

    Wenn ihr wissen wollt, wie ich draufgekommen bin: http://gotw.ca/gotw/006.htm (und auch bei Effective C++): möglichst alle nicht-builtin-Rückgabewerte const machen.

    Diese Regel ist heute nicht mehr zu gebrauchen und war früher mindestens streitbar. Das ist auch direkt das erste Wort des vierten Punktes auf der Seite, "arguable".

    wxSkip schrieb:

    @camper: Wenn ich lvalues und rvalues noch nicht verstanden habe (in der Tat verstehe ich die rvalue-Referenzen und das move-Zeug auch noch nicht so gut), hast du dann auch einen Link dazu?

    Artikel:
    http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/
    http://thbecker.net/articles/rvalue_references/section_01.html

    Videos:
    http://skillsmatter.com/podcast/home/move-semanticsperfect-forwarding-and-rvalue-references
    http://channel9.msdn.com/Shows/Going+Deep/C9-Lectures-Stephan-T-Lavavej-Standard-Template-Library-STL-9-of-n



  • wxSkip schrieb:

    Shade Of Mine schrieb:

    verbieten ist immer doof. erlauben ist immer toll.

    Das hätte ich jetzt nicht von einem erfahrenen Programmierer erwartet. ⚠

    Wieso? Nachträglich etwas verbieten kann man immer. Wenn ich ein
    cout<<(a+b).invert();
    nicht mag, mach ich den return typ von op+ einfach const. Fertig.

    Aber von vornherein zu sagen, dass sowas nicht geht - ist schlecht. Es ist wichtig dass der Programmierer gewisse Freiheiten hat sich auszudrücken.

    Denn wie gesagt: gegen Murphy kann man sich auch später schützen. Schlimm ist es nur wenn die Sprachdesigner so paranoid sind, dass man nur den One-True-Way(tm) gehen kann. Und dann stellt sich heraus, dass der nicht immer der beste ist 😉 Deshalb mag ich es, wenn prinzipiell erstmal garnichts verboten wird.

    Wenn wir strenge verbote in C++ hätten, würden wir diese Diskussion ja auch garnicht führen sondern es wie in Java machen und sowieso nur Zeiger herum geben und nur darüber diskutieren ob wir jetzt eine Immutable Klassen brauchen oder eine Mutable 😉



  • @camper: Leuchtet soweit ein. Könnte man nicht so etwas wie Direktinitialisierung bei POD-Typen auch als Wert sehen? (sprich in C++11 std::array<int, 3>({{1,2,3}}) )

    @krümelkacker: Vielen Dank, werde ich mir mal in einer ruhigen Minute (also sehr bald) durchlesen. 👍

    @Shade of Mine: Wie es thenoise (vermutlich) ironisch angedeutet hat: Das C++ hätte const-correctness sicher nicht erst nachträglich eingeführt, weil dadurch Millionen existierende Codezeilen nicht mehr gültig wären :Mitleid:. Klar kann man das wegcasten - aber das könnte man bei konstanten Rückgabetypen auch.

    Shade of Mine schrieb:

    ... dass der Programmierer gewisse Freiheiten hat, sich auszudrücken ...

    Da stimme ich dir zu, aber dann solltest du das mit den "gewissen" Freiheiten nicht durch dein Absolut-Statement zunichte machen.



  • Shade Of Mine schrieb:

    Nachträglich etwas verbieten kann man immer.

    Ne, eigentlich ja andersrum. Die Abwärtskompatibilität bricht man nur äußerst ungern. Nachträglich erlauben geht immer.

    void d() &
    

    Ich hab das noch nie gesehen, hat jemand zufällig einen guten Artikel zu ref qualifiers? Ich kann auf die Schnelle nichts Vernünftiges finden.



  • fdfdg schrieb:

    ...hat jemand zufällig einen guten Artikel zu ref qualifiers? Ich kann auf die Schnelle nichts Vernünftiges finden.

    Es gibt sonst nur die offiziellen Proposals und Drafts auf open-std.org. Die Idee ist es, mit solchen Qualifizierern bei Elementfunktionen auch zwischen Lvalues und Rvalues unterscheiden zu können. "Normale" Elementfunktionen machen diesbezüglich keinen Unterschied. Die Qualifizierer beziehen sich auf *this.
    Eine Reihe von Beispielen brachte ich ja schon auf der ersten Seite dieses Threads.

    Die erste Version des Proposals:
    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1821.htm

    Da steht die Motivation drin. Für die endgültigen Regeln guckst Du Dir am besten einen der letzten Proposals an.


Anmelden zum Antworten