Funktionen mit RValue Referenzen als Parameter



  • Ich habe die konkrete Implementierung von den Assignment Ops und Konstruktoren hier im Forum rausgelassen und durch ... ersetzt. Habe sie nachgetragen. Hoffe, dass die Implementierung korrekt ist.
    Was meinst Du mit SIZE? Habe SIZE mit ARRAYSIZE ersetzt.



  • So ganz werde ich da nicht schlau. Unten habe ich mal Protokoll drangehängt.
    Die Ausgaben aller Aufrufe bis auf aufrufRValueReferenz(std::move(m1)) sind mir klar. So wie es in dem Protokoll aussieht gibt es keine Unterschied zwischen aufrufReferenz(m1) und aufrufRValueReferenz(std::move(m1)).

    Ursprünglichs Objekt:
    Adresse von diesem Objekt: 0x7ffc2f0b7920
    Adresse von dem Zeiger: 0x7ffc2f0b7920
    Wert von p: 0x5555de580eb0
    Adresse von b: 0x7ffc2f0b7928
    Wert von b: 4

    aufrufRValueReferenz(std::move(m1))
    Print in aufrufRValueReferenz
    Adresse von diesem Objekt: 0x7ffc2f0b7920
    Adresse von dem Zeiger: 0x7ffc2f0b7920
    Wert von p: 0x5555de580eb0
    Adresse von b: 0x7ffc2f0b7928
    Wert von b: 4
    Print Ende in aufrufRValueReferenz

    aufrufReferenz(m1)
    Print in aufrufReferenz
    Adresse von diesem Objekt: 0x7ffc2f0b7920
    Adresse von dem Zeiger: 0x7ffc2f0b7920
    Wert von p: 0x5555de580eb0
    Adresse von b: 0x7ffc2f0b7928
    Wert von b: 4
    Print Ende in aufrufReferenz

    aufrufValue(m1);
    Copy constructor
    Print in aufrufValue
    Adresse von diesem Objekt: 0x7ffc2f0b7930
    Adresse von dem Zeiger: 0x7ffc2f0b7930
    Wert von p: 0x5555de5812f0
    Adresse von b: 0x7ffc2f0b7938
    Wert von b: 4
    Print Ende in aufrufValue

    aufrufValue(std::move(m1));
    Move Constructor
    Print in aufrufValue
    Adresse von diesem Objekt: 0x7ffc2f0b7930
    Adresse von dem Zeiger: 0x7ffc2f0b7930
    Wert von p: 0x5555de580eb0
    Adresse von b: 0x7ffc2f0b7938
    Wert von b: 4
    Print Ende in aufrufValue

    //Ursprüngliches Objekt nach Aufruf des Move-Konstruktors beschädigt, da Wert des Pointer 0 bzw. nullptr
    Adresse von diesem Objekt: 0x7ffc2f0b7920
    Adresse von dem Zeiger: 0x7ffc2f0b7920
    Wert von p: 0
    Adresse von b: 0x7ffc2f0b7928
    Wert von b: 4



  • @asd1 sagte in Funktionen mit RValue Referenzen als Parameter:

    Was meinst Du mit SIZE? Habe SIZE mit ARRAYSIZE ersetzt.

    Ich hatte angenommen, dass der Konstruktor mit int Parameter ein Array mit anderer Größe anlegen sollte.



  • @asd1 sagte in Funktionen mit RValue Referenzen als Parameter:

    So ganz werde ich da nicht schlau.

    Ersetzte deine main Funktion durch

    int main() {
    
       MoveClass m1;
       m1.setArray();
       m1.print();
       std::cout<<std::endl;
       aufrufReferenz(m1);
       aufrufValue(m1);
       aufrufRValueReferenz(std::move(m1)); // Reihenfolge! Nach dem move ist p == nullptr!
       m1.print();
    
       std::cout << "======\n";
       
       MoveClass m2;
    
       aufrufValue(std::move(m2)); // Hier wird nicht kopiert!
    
       m2.print();
    }
    

    ersetze aufrufRValueReferenz durch

    void aufrufRValueReferenz(MoveClass&& moved) // hier wird kein neues Objekt erzeugt 
    {
      MoveClass m( std::move(moved)); // erst hier ist der "move" komplett
      std::cout <<"Print in aufrufRValueReferenz"<<std::endl;
      m.print();
      std::cout <<"Print Ende in aufrufRValueReferenz"<<std::endl<<std::endl;
    }
    

    Vielleicht helfen die Kommentare weiter



  • @asd1 sagte in Funktionen mit RValue Referenzen als Parameter:

    //Destructor
    ~MoveClass()
    {
        std::cout <<"Destructor"<<std::endl;
        delete[] p;
        p= nullptr;
    }
    

    OT: p= nullptr; ist völlig überflüssig. p ist nach } nicht mehr da!



  • @manni66 sagte in Funktionen mit RValue Referenzen als Parameter:

    @asd1 sagte in Funktionen mit RValue Referenzen als Parameter:

    Was meinst Du mit SIZE? Habe SIZE mit ARRAYSIZE ersetzt.

    Ich hatte angenommen, dass der Konstruktor mit int Parameter ein Array mit anderer Größe anlegen sollte.

    Nö, bezieht sich auf b.



  • @manni66 sagte in Funktionen mit RValue Referenzen als Parameter:

    @asd1 sagte in Funktionen mit RValue Referenzen als Parameter:

    //Destructor
    ~MoveClass()
    {
        std::cout <<"Destructor"<<std::endl;
        delete[] p;
        p= nullptr;
    }
    

    OT: p= nullptr; ist völlig überflüssig. p ist nach } nicht mehr da!

    Stimmt.



  • @manni66 sagte in Funktionen mit RValue Referenzen als Parameter:

    @asd1 sagte in Funktionen mit RValue Referenzen als Parameter:

    So ganz werde ich da nicht schlau.

    Ersetzte deine main Funktion durch

    int main() {
    
       MoveClass m1;
       m1.setArray();
       m1.print();
       std::cout<<std::endl;
       aufrufReferenz(m1);
       aufrufValue(m1);
       aufrufRValueReferenz(std::move(m1)); // Reihenfolge! Nach dem move ist p == nullptr!
       m1.print();
    
       std::cout << "======\n";
       
       MoveClass m2;
    
       aufrufValue(std::move(m2)); // Hier wird nicht kopiert!
    
       m2.print();
    }
    

    ersetze aufrufRValueReferenz durch

    void aufrufRValueReferenz(MoveClass&& moved) // hier wird kein neues Objekt erzeugt 
    {
      MoveClass m( std::move(moved)); // erst hier ist der "move" komplett
      std::cout <<"Print in aufrufRValueReferenz"<<std::endl;
      m.print();
      std::cout <<"Print Ende in aufrufRValueReferenz"<<std::endl<<std::endl;
    }
    

    Vielleicht helfen die Kommentare weiter

    Danke! Ich werde mir das gleich in Ruhe anschauen.



  • OK. Danke.
    Dann hätte ich eine weitere Frage.

    // Aufruf über Referenz
    void aufrufReferenz(MoveClass& moved)
    {
        MoveClass m( std::move(moved)); //Neu hinzugkommen
        std::cout <<"Print in aufrufReferenz"<<std::endl;
        moved.print();
        std::cout <<"Print Ende in aufrufReferenz"<<std::endl;
    }
    

    Hätte doch denselben Effekt mit aufrufReferenz(m1)? Einzige Unterschied wäre, dass man nur LValue Referenzen angeben darf. aufrufReferenz(Moveclass(4)) wäre zum Beispiel nicht möglich.



  • @manni66 sagte in Funktionen mit RValue Referenzen als Parameter:

    @asd1 sagte in Funktionen mit RValue Referenzen als Parameter:

    So ganz werde ich da nicht schlau.

    Ersetzte deine main Funktion durch

    int main() {
    
       MoveClass m1;
       m1.setArray();
       m1.print();
       std::cout<<std::endl;
       aufrufReferenz(m1);
       aufrufValue(m1);
       aufrufRValueReferenz(std::move(m1)); // Reihenfolge! Nach dem move ist p == nullptr!
       m1.print();
    
       std::cout << "======\n";
       
       MoveClass m2;
    
       aufrufValue(std::move(m2)); // Hier wird nicht kopiert!
    
       m2.print();
    }
    

    ersetze aufrufRValueReferenz durch

    void aufrufRValueReferenz(MoveClass&& moved) // hier wird kein neues Objekt erzeugt 
    {
      MoveClass m( std::move(moved)); // erst hier ist der "move" komplett
      std::cout <<"Print in aufrufRValueReferenz"<<std::endl;
      m.print();
      std::cout <<"Print Ende in aufrufRValueReferenz"<<std::endl<<std::endl;
    }
    

    Vielleicht helfen die Kommentare weiter

    Wenn ich richtig verstanden habe, ist der Sinn für

    void aufrufRValueReferenz(MoveClass&& moved)
    

    den Move-Konstruktor bzw. Move Assignment in der Funktion einzusetzen. Ist das richtig?



  • @asd1 sagte in Funktionen mit RValue Referenzen als Parameter:

        // Copy constructor
        MoveClass(const MoveClass &other):b{other.b}
        {
            std::cout <<"Copy constructor"<<std::endl;
            p=new int[ARRAYSIZE];
            for (int i=0; i<ARRAYSIZE; i++)
            {
                p[i]=other.p[i];
            }
        }
    
    // ...
    
        MoveClass& operator=(const MoveClass &other)
        {
            std::cout <<"Assignment operator"<<std::endl;
            b=other.b;
            delete[] p;
            p=new int[ARRAYSIZE];
            for (int i=0; i<ARRAYSIZE; i++)
            {
                p[i]=other.p[i];
            }
            return *this;
        }
    

    Fällt dir auf daß da was doppelt ist? Ist auch nicht exception-safe. Google mal nach dem Copy and Swap Idiom.



  • @asd1 sagte in Funktionen mit RValue Referenzen als Parameter:

    Hätte doch denselben Effekt mit aufrufReferenz(m1)?

    Ja. Man sieht dem Funktionsaufruf aber nicht an, dass das Objekt danach nicht mehr zu gebrauchen ist.



  • @asd1 sagte in Funktionen mit RValue Referenzen als Parameter:

    den Move-Konstruktor bzw. Move Assignment in der Funktion einzusetzen. Ist das richtig?

    Man kann auch eine andere Funktion aufrufen, die die Referenz annimmt.


Anmelden zum Antworten