Lets say we have the following code:
std::vector<int> f()
{
std::vector<int> y;
...
return y;
}
std::vector<int> x = ...
x = f();
It seems the compiler has two approaches here:
(a) NRVO: Destruct x, then construct f() in place of x.
(b) Move: Construct f() in temp space, move f() into x, destruct f().
Is the compiler free to use either approach, according to the standard?
The compiler may NRVO into a temp space, or move construct into a temp space. From there it will move assign x
.
Update:
Any time you're tempted to optimize with rvalue references, and you're not positive of the results, create yourself an example class that keeps track of its state:
And run that class through your test. For example:
#include <iostream>
#include <cassert>
class A
{
int state_;
public:
enum {destructed = -2, moved_from, default_constructed};
A() : state_(default_constructed) {}
A(const A& a) : state_(a.state_) {}
A& operator=(const A& a) {state_ = a.state_; return *this;}
A(A&& a) : state_(a.state_) {a.state_ = moved_from;}
A& operator=(A&& a)
{state_ = a.state_; a.state_ = moved_from; return *this;}
~A() {state_ = destructed;}
explicit A(int s) : state_(s) {assert(state_ > default_constructed);}
friend
std::ostream&
operator<<(std::ostream& os, const A& a)
{
switch (a.state_)
{
case A::destructed:
os << "A is destructed\n";
break;
case A::moved_from:
os << "A is moved from\n";
break;
case A::default_constructed:
os << "A is default constructed\n";
break;
default:
os << "A = " << a.state_ << '\n';
break;
}
return os;
}
friend bool operator==(const A& x, const A& y)
{return x.state_ == y.state_;}
friend bool operator<(const A& x, const A& y)
{return x.state_ < y.state_;}
};
A&& f()
{
A y;
return std::move(y);
}
int main()
{
A a = f();
std::cout << a;
}
If it helps, put print statements in the special members that you're interested in (e.g. copy constructor, move constructor, etc.).
Btw, if this segfaults on you, don't worry. It segfaults for me too. Thus this particular design (returning an rvalue reference to a local variable) is not a good design. On your system, instead of segfaulting, it may print out "A is destructed". This would be another sign that you don't want to do this.