It's an optimization permitted by the C++ Standard.
The C++ standard draft, [class.temp/2] says and I quote (relevant parts only; emphasis are mine):
The materialization of a temporary object is generally delayed as long
as possible in order to avoid creating unnecessary temporary objects.
.....
Example:
class X {
public:
X(int);
X(const X&);
X& operator=(const X&);
~X();
};
class Y {
public:
Y(int);
Y(Y&&);
~Y();
};
X f(X);
Y g(Y);
void h() {
X a(1);
X b = f(X(2));
Y c = g(Y(3));
a = f(a);
}
X(2)
is constructed in the space used to hold f()
's argument and
Y(3)
is constructed in the space used to hold g()
's argument.
Formerly, in n3690, it said:
An implementation might use a temporary in which to construct X(2)
before passing it to f()
using X
’s copy constructor;
alternatively, X(2)
might be constructed in the space used to hold
the argument
That means, this:
void go(Foo) {
std::cout << "go" << std::endl;
}
int main() {
go(Foo());
}
is sometimes as "performant" as you want!, See, C++ is gradually getting there ;-).
But you see, using std::move
will inhibit that behavior, because std::move
produces an xvalue
expression from a materialized object:
void go(Foo) {
std::cout << "go" << std::endl;
}
int main() {
go(std::move(Foo()));
}
In conclusion,
When not using std::move
in this your case, the object is created once as seen Live on Coliru
But when you use std::move
, it is created twice as seen Live on Coliru, this is because of materialization of the object. Read the complete paragraph of class.temp/2 to understand what materialization means.