C++ Pendant zu Java Objekt Referenz



  • Bzw. s. Copy elision



  • @CppConst sagte in C++ Pendant zu Java Objekt Referenz:

    Damit RVO greifen kann, muss meine Objekt aber einen Move Konstruktor haben, oder?

    Bei RVO + copy-elision wird das Objekt direkt dort erstellt wo es dann nach dem Funktionsaufruf "weiterleben" soll.

    Foo makeFoo() {
        Foo f{"blah"}; // 1
        f.something(1);
        f.somethingElse(1, 2, 3);
        return f; // Hier KEIN std::move() - mit move würde man NRVO _verhindern_
    }
    
    void fun() {
        Foo foo{makeFoo()}; // 2
    }
    

    Das Objekt das in (1) erstellt wird, wird also direkt im Speicher der Variable von Zeile (2) erstellt. Hier wird weder ein Move-Konstruktor noch ein Copy-Konstruktor verwendet.



  • Danke für die genaue Erklärung, so langsam begreife ich es. Ist nicht so einfach C++ richtig zu verstehen. Ich habe zwar schon einige Sachen mit C++ gemacht, habe mir allerdings über solche Dinge keine Gedanken gemacht, bis ich so ein CppCon Video gesehen hatte, wo es darum ging wie man Overhead vermeiden kann, dann kamen die Fragen und nun möchte ich C++ besser kennen lernen.


  • Mod

    Ergänzung:

    Foo makeFoo() {
        Foo f{"blah"}; // 1
        f.something(1);
        f.somethingElse(1, 2, 3);
        return f; // Hier KEIN std::move() - mit move würde man NRVO _verhindern_
    }
    

    Tatsächlich garantierte der Standard vor guaranteed copy elision (also vor C++17) ab C++11, dass der identifier f ein rvalue ist. D.h. move(f) war implizit. Es haette also schon rein technisch niemals geholfen, das zu schreiben (abgesehen davon, dass NRVO lange vor guaranteed copy elision implementiert war).



  • Spannend wird es nur hier:

    Foo makeFoo(bool condition) {
        Foo f1{"blah"};
        Foo f2{"blubberdieblubb"};
    
        // [code...]
    
        // a)
        return condition ? f1 : f2;
        // b)
        return std::move(condition ? f1 : f2);
    }
    
    

    Hier ist rechts ja ein ?-:-Konstrukt. Mit so einer Konstruktion verbaut man sich das automatische move.


  • Mod

    Also theoretisch könnte man einen absoluten Grossteil der Verwendungen eines automatischen Objektes in return statements durch einen Move ersetzen. Es gibt aber eben auch Ausnahmen (überwiegend realitätsferner Natur...) und deshalb ist es nur fuer simple Identifier gegeben.



  • @Columbo sagte in C++ Pendant zu Java Objekt Referenz:

    Es haette also schon rein technisch niemals geholfen, das zu schreiben

    Richtig. Ich hab das Kommentar bloss dazugeschrieben weil es in dem Fall nicht nur unnütz ist sondern sogar schadet.


  • Mod

    @hustbaer ich weiss, deshalb ja auch als "Ergänzung" 🙂



  • @wob sagte in C++ Pendant zu Java Objekt Referenz:

    Spannend wird es nur hier:

    Foo makeFoo(bool condition) {
        Foo f1{"blah"};
        Foo f2{"blubberdieblubb"};
    
        // [code...]
    
        // a)
        return condition ? f1 : f2;
        // b)
        return std::move(condition ? f1 : f2);
    }
    
    

    Hier ist rechts ja ein ?-:-Konstrukt. Mit so einer Konstruktion verbaut man sich das automatische move.

    Also wenn nicht klar ist welches Objekt zurückgegeben wird, ist es sinnvoller mit move zu arbeiten um Kopien zu vermeiden?



  • @CppConst sagte in C++ Pendant zu Java Objekt Referenz:

    Also wenn nicht klar ist welches Objekt zurückgegeben wird, ist es sinnvoller mit move zu arbeiten um Kopien zu vermeiden?

    Im Allgemeinen vermutlich ja.

    Wobei man den Code auch u.U. umschreiben kann. Wenn f1 und f2 in [code...] nicht gebraucht werden, dann wäre es besser zu schreiben:

    Foo makeFoo(bool condition) {
        // [code...]
        if (condition)
            return {"blah"};
        else
            return {"blubberdieblubb"};
    }
    

    Denn dann greift wieder RVO, und man spart sich das 2. unnötige Foo Objekt zu erzeugen. (Diesmal wirklich RVO und nicht NRVO.)


Log in to reply