Ответ 1
Компилятор может использовать NRVO в временном пространстве или перемещать конструкцию в временное пространство. Оттуда он переместит назначение x
.
Update:
В любое время, когда у вас возникает соблазн оптимизировать ссылки rvalue, и вы не уверены в результатах, создайте себе примерный класс, который отслеживает его состояние:
- построен
- построено по умолчанию
- перемещен из
- подорванный
И запустите этот класс через свой тест. Например:
#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;
}
Если это помогает, поместите инструкции печати в специальные члены, которые вас интересуют (например, конструктор копирования, перемещение конструктора и т.д.).
Btw, если это вам не поможет, не волнуйтесь. Это тоже для меня. Таким образом, эта конкретная конструкция (возвращающая ссылку rvalue на локальную переменную) не является хорошим дизайном. В вашей системе вместо segfault, он может распечатывать "A разрушен". Это было бы еще одним признаком того, что вы не хотите этого делать.