L- und R- Value Referenzen?



  • Hallo ich habe eine verkettete Liste und muss da R-Value Referenz einbauen. Daher möchte ich den Unterschied der Referenzen endlich verstehen.ausserdem wie implementiert man eine r-value Referenz?
    Habe bisher nichts gefunden dass wir wirklich weiterhilft

    Vielen dank im vorraus.





  • AnfaengerCpp schrieb:

    Hallo ich habe eine verkettete Liste und muss da R-Value Referenz einbauen.

    Warum glaubst du das machen zu müssen? Bzw was genau meinst du damit?

    AnfaengerCpp schrieb:

    ausserdem wie implementiert man eine r-value Referenz?

    Das ist gar nicht Deine Aufgabe. Das machen Compiler-Hersteller. Oder was meinst Du hier mit "implementiert"?



  • AnfaengerCpp schrieb:

    Daher möchte ich den Unterschied der Referenzen endlich verstehen.

    Ne R-Value ist im Prinzip ein Ding das keinen Namen hat. Also z.B. ein Returnwert oder ein Temporary das von einem Ausdruck ala a + b erzeugt wird.
    Ne L-Value ist dann etwas was sehr wohl einen Namen hat, bzw. über etwas was einen Namen hat angesprochen werden kann. Also z.B. ein Objekt das von einer Variable representiert wird ist ne L-Value, oder auch ein Objekt an das man über Dereferenzierung eines Zeigers drankommt.

    Daraus folgt dass du sozusagen nur eine Chance hast auf eine R-Value zuzugreifen, und danach wird sie einfach irgendwann zerstört (IIRC meist als letzter Schritt der Ausführung des Statements in dem die R-Value entstanden ist).
    Und genau diesen Umstand kann man jetzt ausnutzen: wenn man weiss dass ein Ding sowieso gleich zerstört wird, ohne dass irgend ein anderer Programmteil dazwischen noch eine Chance hätte darauf zuzugreifen, dann kann man das Ding "ausschlachten".

    In einem Kopierkonstruktor kann das z.B. Sinn machen, wenn die Klasse dynamisch irgendwelche Resourcen (Speicher, ...) anfordert. Anstatt neue Resourcen anzufordern kann man, wenn man eine R-Value übergeben bekommt, diese Resourcen einfach der R-Value klauen.

    Und deswegen gibt es die sog. R-Value Referenzen, die nur an R-Values binden aber nicht an L-Values.
    D.h. du schreibst einen Kopierkonstruktor der eine R-Value Referenz nimmt, und der kann dann seinem Parameter die Resourcen klauen. Dieser Vorgang, also das Erstellen einer "Kopie" durch beklauen eines Originals nennt man dann "move" - weil's von der Semantik her mehr oder weniger einer Verschiebung des Objekts entspricht. Das was das alte Objekt hatte hat dann das neue, und das alte ist leer.

    Meistens macht man dann noch zusätzlich einen Kopierkonstruktor der eine L-Value Referenz und "wie gewohnt" arbeitet.
    Den kann man aber auch weglassen, dann hat man eine sog. "move only" Klasse. Das ist praktisch in Fällen wo man unkopierbare Objekte hat, bei denen es aber trotzdem Sinn machen kann sie von einer Stelle an eine andere zu übergeben.
    Ohne R-Value Referenzen ist die einzige Möglichkeit das sauber abzubilden dass man das Objekt dynamisch anlegt und dann Zeiger übergibt (egal jetzt ob rohe oder Smart-Pointer).
    Mit R-Value Referenzen kann man sich die Zeiger und die dynamische Speicheranforderung für diese Art von Objekten sparen.



  • @krümelkacker:
    Naja für Dinge die ähnlich wie std::list sind kann Move-Support schon toll sein. Und ich denke genau das wird auch gemeint sein: der Klasse Move-Support zu verpassen.
    Wobei ich auch der Meinung bin dass die Formulierung äusserst sub-optimal ist -- meine Interpretation ist ja auch mehr geraten als sicher 😉



  • D.h. du schreibst einen Kopierkonstruktor der eine R-Value Referenz nimmt, und der kann dann seinem Parameter die Resourcen klauen.

    Das ist dann ein Move-Konstruktor.

    Ne L-Value ist dann etwas was sehr wohl einen Namen hat, bzw. über etwas was einen Namen hat angesprochen werden kann.

    Merkwuerdige Erklaerung, u.a. weil man sowieso auf alles mit einem Namen zugreifen muss (wie willst du ohne irgendwelche Namen zu nutzen auf etwas zugreifen?).

    Ausserdem ist ein lvalue (bemerke den Artikel!) ein Ausdruckstyp, und hat nie einen Namen. Der Name einer Variable ist jedoch immer ein lvalue:

    std::string i; // i ist eine Variable vom Typ std::string; Der Ausdruck 'i' ist ein lvalue
    auto&& ri = std::move(i); // ri ist eine rvalue-Referenz auf std::string; 'ri' ist ein lvalue. 'std::move(i)' ist ein rvalue.
    


  • Oh Mann Arcoth nerv mich nicht.

    Du glaubst doch hoffentlich nicht dass ich dich als Authorität in Sachen Geschlecht von Fremdwörtern anerkenne? Falls doch lass mich dieses Misverständnis schnell korrigieren: nein, ich tu' es nicht.

    Arcoth_logoff schrieb:

    Das ist dann ein Move-Konstruktor.

    Ja, richtig.

    Ne L-Value ist dann etwas was sehr wohl einen Namen hat, bzw. über etwas was einen Namen hat angesprochen werden kann.

    Merkwuerdige Erklaerung, u.a. weil man sowieso auf alles mit einem Namen zugreifen muss (wie willst du ohne irgendwelche Namen zu nutzen auf etwas zugreifen?).

    Du scheinst irgendwie ziemlich weit hinterm Berg zu wohnen, hm? Die Erklärung ist ungenau (d.h. strenggenommen falsch), aber die wohl üblichste einfache (und meist ausreichend genaue) Erklärung die ich kenne.

    Was hat bitte das Ergebnis des Ausdrucks a + b für einen Namen? a + b etwa? Das sind zwei Namen.
    Ersetze Name mit Bezeichner wenn dir der Ausdruck Name nicht passt.

    Ausserdem ist ein lvalue (bemerke den Artikel!) ein Ausdruckstyp, und hat nie einen Namen.

    Du kannst dich echt dumm stellen manchmal.

    Viel mehr mag ich dazu jetzt auch net schreiben, also zitier ich lieber was...

    http://msdn.microsoft.com/en-us/library/f90831hc(v=vs.110).aspx

    MSDN Lvalues and Rvalues schrieb:

    Every C++ expression is either an lvalue or an rvalue. An lvalue refers to an object that persists beyond a single expression. You can think of an lvalue as an object that has a name. All variables, including nonmodifiable (const) variables, are lvalues. An rvalue is a temporary value that does not persist beyond the expression that uses it.



  • hustbaer schrieb:

    http://msdn.microsoft.com/en-us/library/f90831hc(v=vs.110).aspx

    MSDN Lvalues and Rvalues schrieb:

    An rvalue is a temporary value that does not persist beyond the expression that uses it.

    Das ist absoluter Quatsch! Microsoft sollte die Leute entlassen, die so etwas schreiben! Weil sie offensichtlich keine Ahnung haben!!!

    — An rvalue (so called, historically, because rvalues could appear on the right-hand side of an assignment expressions) is an xvalue, a temporary object (12.2) or subobject thereof, or a value that is not associated with an object.

    Waere ja fuerchterlich, wenn std::move(str); den String als indeterminate value zuruecklassen wuerde!!!



  • arkot333 schrieb:

    hustbaer schrieb:

    http://msdn.microsoft.com/en-us/library/f90831hc(v=vs.110).aspx

    MSDN Lvalues and Rvalues schrieb:

    An rvalue is a temporary value that does not persist beyond the expression that uses it.

    Das ist absoluter Quatsch! Microsoft sollte die Leute entlassen, die so etwas schreiben! Weil sie offensichtlich keine Ahnung haben!!!

    Aber ich dachte so war es ursprünglich? Wenn ich z.B. Scott Meyer richtig verstanden habe, dann wurde im Hintergrund ein temporäres Objekt erzeugt, von dem in das neue Objekt kopiert wurde. Anschließend wurde dieses temp. Objekt wieder zerstört.

    Und nun besagt std::move gerade den umständlichen Kopiervorgang zu überspringen und das temp. Objekt als das neue Objekt zu übernehmen in das man ohnehin hineinkopiert hätte.

    Wenn ich allerdings Mr. STL richtig verstanden habe, dann ist das nicht mehr exception safe. Denn bei einem Kopiervorgang wird nur etwas kopiert, d.h. wenn dieser Vorgang unterbrochen wird ist immerhin noch das Original vorhanden, aus dem man kopiert hätte.
    Bei dem std::move Vorgang ist dann allerdings die Information futsch und es lässt sich nicht rekonstrouieren.

    Gruß,
    -- Klaus.



  • Klaus82 schrieb:

    Wenn ich allerdings Mr. STL richtig verstanden habe

    Nein, du hast falsch verstanden. Bei dem Kopieren ging es vermutlich um std::move_if_noexcept beim Container vergrössernl.

    std::move ist nur ein Cast eines lvalues in ein rvalue, nicht mehr.



  • mrstl schrieb:

    std::move ist nur ein Cast eines lvalues in ein rvalue, nicht mehr.

    Ja, um den move constructor zu triggern. Also anstatt wie früher: "Hier hast du ein Objekt, kopier daraus mal die Daten" sagt man jetzt "hier hast du ein Objekt ... nimm es!"

    Gruß,
    -- Klaus.


  • Mod

    Und nun besagt std::move gerade den umständlichen Kopiervorgang zu überspringen und das temp. Objekt als das neue Objekt zu übernehmen in das man ohnehin hineinkopiert hätte.

    Ein explizites move ist gar nicht immer nötig. Bei einer Zuweisung der Form

    A a = rvalue
    

    wird automatisch der Move-Konstruktor ausgewählt

    Die Erklärung ist ungenau (d.h. strenggenommen falsch)

    Wieso nicht gleich richtig schreiben?

    Was hat bitte das Ergebnis des Ausdrucks a + b für einen Namen? a + b etwa? Das sind zwei Namen.

    Ich rede von Zugriffen.



  • Arcoth schrieb:

    Die Erklärung ist ungenau (d.h. strenggenommen falsch)

    Wieso nicht gleich richtig schreiben?

    Will sehen. Schreib es richtig. In kurz und verständlich.

    Was hat bitte das Ergebnis des Ausdrucks a + b für einen Namen? a + b etwa? Das sind zwei Namen.

    Ich rede von Zugriffen.

    Ja und? Ich nicht.
    Davon abgesehen bleibt es Quatsch. Mit was für einem Namen greifst du auf die Rvalue "a + b" zu?


  • Mod

    hustbaer schrieb:

    Arcoth schrieb:

    Die Erklärung ist ungenau (d.h. strenggenommen falsch)

    Wieso nicht gleich richtig schreiben?

    Will sehen. Schreib es richtig. In kurz und verständlich.

    Gut, ich muss mich entschuldigen. Deine Erklärung ist natürlich auch nicht wirklich falsch. Aber es gibt doch die klassische Erklärung, die ganz eindeutig ist:

    lvalues sind Ausdrücke, die auf der linken Seite einer Zuweisung stehen können. rvalues können nur auf der rechten stehen.

    Ebenfalls nur grob. Dann war meine Kritik an dich natürlich unberechtigt, das tut mir Leid.

    Man kann aber eine Liste der Dinge machen, die lvalues sind:
    lvalues:
    - Variablennamen
    - Funktionsnamen
    - Pointerdereferenzierung
    - Arrayzugriff (=> Pointer....)
    - ...

    Funktionsaufrufe sind abhängig vom Rückgabetypen l- oder r-values. Usw.

    Ja und? Ich nicht.

    Aber du hast mich zitiert. 🙂

    Mit was für einem Namen greifst du auf die Rvalue "a + b" zu?

    Mit keinem. Aber die Formulierung ist irreführend. Zugriff impliziert irgendwie, dass der Wert irgendwo länger gespeichert ist.
    Gut, das ist Blödsinn, und du hattest Recht.


Anmelden zum Antworten