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
}
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();
.
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.
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.