Somewhat surprisingly (to me), the following two programs compile to different outputs, with the latter one having much better performance (tested with gcc and clang):
#include <vector>
int main()
{
std::vector<int> a(2<<20);
for(std::size_t i = 0; i != 1000; ++i) {
std::vector<int> b(2<<20);
a = b;
}
}
vs.
#include <vector>
int main()
{
std::vector<int> a(2<<20);
for(std::size_t i = 0; i != 1000; ++i) {
std::vector<int> b(2<<20);
a = std::move(b);
}
}
Could someone explain to me why the compiler does (or can) not automatically consider b
an xvalue in the last assignment and apply move semantics without the explicit std::move
cast?
Edit: Compiled with (g++|clang++) -std=c++11 -O3 -o test test.cpp
Compilers can't break the as-if rule
As §1.9/1 states:
The semantic descriptions in this International Standard define a parameterized nondeterministic abstract machine. This International Standard places no requirement on the structure of conforming implementations. In particular, they need not copy or emulate the structure of the abstract machine. Rather, conforming implementations are required to emulate (only) the observable behavior of the abstract machine as explained below
i.e. a compiler can't change the observable behavior of the program. Automatically (even if with no repercussions) converting an assignment to a move assignment would break this statement.
Copy elisions can slightly alter this behavior, but that is regulated by §12.8/31.
If you want to use the move version, you'll have to explicitly ask for it as in the latter example.
Let's look at the next sample (please ignore void
return type from operator=
):
#include <iostream>
struct helper
{
void operator=(helper&&){std::cout<<"move"<<std::endl;}
void operator=(const helper&){std::cout<<"copy"<<std::endl;}
};
void fun()
{
helper a;
{
helper b;
a = b;
}
}
void gun()
{
helper a;
{
helper b;
a = std::move(b);
}
}
int main()
{
fun();
gun();
}
The operator=
has different behaviour depending on its arguments. The compiler is allowed to optimise the code only if it is able to maintain the observable behaviour the same.
Considering b
from fun
an xvalue
, while it isn't an xvalue
at the moment of the call it will change the observable behaviour of the program and this is not desired nor allowed by the standard.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With