std::move um rvalue-Referenz?



  • Hallo zusammen,

    also ich möchte ein nicht-kopierbares Objekt per rvalue-Referenz mit unique_ptr
    an einen Konstruktor übergeben.

    Dazu habe ich folgenden Code (wobei ich hier int statt dem nicht-kopierbaren Objekt verwende):

    #include<memory>
    
    class A {
    public:
            A(std::unique_ptr<int>&& ptr) : ptr(std::move(ptr)){}
    
            std::unique_ptr<int> ptr;
    };
    
    int main()
    {
            int* i = new int(0);
            A a(std::move(std::unique_ptr<int>(i)));
            return 0;
    }
    

    Jetzt verstehe ich allerdings nicht, warum in der Initialisierungsliste
    ein std::move um den Parameter muss.

    Dieser ist doch schon eine rvalue-Referenz, oder?
    Kann mich mal jemand aufklären?
    Hab ich evtl. etwas Verbotenes gemacht?

    Gruß,
    XSpille



  • Jetzt verstehe ich allerdings nicht, warum in der Initialisierungsliste
    ein std::move um den Parameter muss.

    Dieser ist doch schon eine rvalue-Referenz, oder?

    Sobald der RValue einen Namen bekommt nicht mehr... Dafür ist ja anschließend das move da, um eben jene "RValueness" aufrecht zu erhalten.

    edit: Sollte RValue heißen, nicht RValue-Referenz



  • Matzer schrieb:

    Jetzt verstehe ich allerdings nicht, warum in der Initialisierungsliste
    ein std::move um den Parameter muss.

    Dieser ist doch schon eine rvalue-Referenz, oder?

    Sobald die RValue-Referenz einen Namen bekommt nicht mehr... Dafür ist ja anschließend das move da, um eben jene "RValueness" aufrecht zu erhalten.

    Kurze aber wertvolle Antwort 👍
    DANKE!!!



  • XSpille schrieb:

    Jetzt verstehe ich allerdings nicht, warum in der Initialisierungsliste
    ein std::move um den Parameter muss.
    Dieser ist doch schon eine rvalue-Referenz, oder?
    Kann mich mal jemand aufklären?
    Hab ich evtl. etwas Verbotenes gemacht?

    Dass diese Art von Referenz "Rvalue-Referenz" heißt, hat nur etwas mit der Initialisierung der Referenz zu tun. Nach der Initialisierung gibt es dann ja einen neuen Namen für das Objekt, worauf sich die Referenz bezieht. Der neue Name stellt einen ganz normalen Lvalue-Ausdruck dar. Das ist Absicht; denn mit diesem neuen Namen kannst Dich noch öfters auf das Objekt beziehen. Es soll absichtlich nicht als Rvalue behandelt werden.

    Upps. Zu spät.



  • krümelkacker schrieb:

    XSpille schrieb:

    Jetzt verstehe ich allerdings nicht, warum in der Initialisierungsliste
    ein std::move um den Parameter muss.
    Dieser ist doch schon eine rvalue-Referenz, oder?
    Kann mich mal jemand aufklären?
    Hab ich evtl. etwas Verbotenes gemacht?

    Dass diese Art von Referenz "Rvalue-Referenz" heißt, hat nur etwas mit der Initialisierung der Referenz zu tun. Nach der Initialisierung gibt es dann ja einen neuen Namen für das Objekt, worauf sich die Referenz bezieht. Der neue Name stellt einen ganz normalen Lvalue-Ausdruck dar. Das ist Absicht; denn mit diesem neuen Namen kannst Dich noch öfters auf das Objekt beziehen. Es soll absichtlich nicht als Rvalue behandelt werden.

    Upps. Zu spät.

    Es ist niemals zu spät 😉

    Stimmt... Ansonsten würde mein Objekt bei allen Aufrufen schon als Rvalue-Referenz
    interpretiert (ohne es bewusst zu merken), obwohl ich es erst am Ende
    für den Move-Konstruktor verwenden möchte...



  • Eine Frage bleibt noch 🙂

    Werdet ihr den unique_ptr zukünftig benutzen um zu verdeutlichen,
    dass ein Objekt den Besitz beansprucht?



  • In meinen Augen ziemlich gute und umfassende Erklärung von r-Refs, rvalueness, lvalueness, std::move usw.:
    http://blogs.msdn.com/b/vcblog/archive/2009/02/03/rvalue-references-c-0x-features-in-vc10-part-2.aspx



  • Den Blog-Artikel hatte ich auch gelesen. Fand ich gut. Aber es gab Ende 2009 ein "R-Value References Update". Der Artikel beschreibt also nicht die aktuellen Regeln:

    The modifiable rvalue reference, Type&& , is willing to bind to modifiable lvalues and modifiable rvalues, but not to const lvalues and const rvalues (which would violate const correctness).

    The const rvalue reference, const Type&& , is willing to bind to everything.

    Das fettgedruckte ist jetzt nach der Regeläderung von vor einem Jahr falsch. In der Artikelserie von Dave Abrahams gibt es dazu eine schöne Tabelle, die gleichzeitig erklärt, wie Überladungen aufgelöst werden:

    Dave schrieb:

    |           Expressions            |
    Reference Type |    T    const T     T    const T | Priority
                   | rvalue  rvalue   lvalue  lvalue  |
    ------------------------------------------------------------
             T&&        X                                  4
       const T&&        X       X                          3
             T&                          X                 2
       const T&         X       X        X       X         1
    

    The “Priority” column describes how these references behave with respect to overload resolution.

    Beipsiel zur Überladung

    void f(int&&);      // A
    void f(const int&); // B
    ...
    int lvalue = 17;
    f(29);      // Spalte "T rvalue", A und B zulässig, A hat höhere Priorität --> A
    f(lvalue);  // Spalte "T lvalue", nur B zulässig                           --> B
    

Anmelden zum Antworten