Search code examples
c++rvalue-referencemove-constructorcopy-elision

Cast to rvalue reference prevents copy elision


I read more related articles, but none of the answers clarified my doubts. Why in the code below the optimization takes place only when there is no cast to an rvalue reference, otherwise either the move (whether provided) or the copy (if there is no move constructor provided) constructor is called.

struct Clasa{
    Clasa(){
        std::cout << "Default" << std::endl;
    }
    Clasa(const Clasa& clasa){
        std::cout << "Copy" << std::endl;
    }
    Clasa(Clasa&& clasa){
        std::cout << "Move" << std::endl;
    }
    ~Clasa(){
        std::cout << "Destructor" << std::endl;
    }
};

int main(){
    Clasa c = (Clasa&&)Clasa();//no optimization
    Clasa d = Clasa();//move/copy elision
} 

Solution

  • In the first case, Clasa c = (Clasa&&)Clasa(); temporary materialization takes place as you're explicitly binding a reference to a prvalue(Class()) and thus no elision here . This can be seen from temporary materialization:

    Temporary materialization occurs in the following situations:

    • when binding a reference to a prvalue;

    Now coming to the second case of Clasa d = Clasa();.

    C++17 & Onwards

    Starting from C++17 there is mandatory copy elision. This means that it is mandated by the standard that the object is constructed directly into the storage where it would otherwise be copied/moved to. This essentially means that no copy/move call will be observed here.

    Pre-C++17

    But prior to C++17, this may result in the creation of a temporary using which d is copy initialized. The same is explained in more detail here.