省流:不管看起来好像fun里面的局部变量a好像被“移动“出来了,但a在除了它所在的作用域后立刻就释放了,move出来的变量已经指向了“空悬”的对象。再访问的话程序将产生不可预知行为。
struct DPoint3d
{
//! x coordinate
double x;
//! y coordinate
double y;
//! z coordinate
double z;
DPoint3d() = default;
~DPoint3d()
{
std::cout << "~DPoint3d" << endl;
}
DPoint3d(const DPoint3d& pt)
{
std::cout << "123" << endl;
x = pt.x;
y = pt.y;
z = pt.z;
}
DPoint3d(const DPoint3d&& pt)
{
std::cout << "456" << endl;
x = pt.x;
y = pt.y;
z = pt.z;
}
DPoint3d& operator=(DPoint3d&& pt) {
std::cout << "789" << endl;
x = pt.x;
y = pt.y;
z = pt.z;
}
};
DPoint3d&& fun()
{
DPoint3d a; // 默认构造
a.x = 1;
a.y = 2;
a.z = 3;
// return a; // 报错:无法将左值绑定到右值引用
return std::move(a); // 返回右值引用,没有进行构造
}
int main()
{
DPoint3d&& a = fun();
std::cout << a.x << endl;
}
编译成功,可以运行,但这种代码是有问题的:
刚执行完DPoint3d&& a = fun();的时候,调试器还能显示值:
再执行一步,就现出原型了:
其实,除了fun函数之后,a立刻就析构了:
代码改一下,加入移动构造函数。注意第一个DPoint3d&& c = std::move(b);不会调用任何移动构造函数,为什么呢:
struct DPoint3d
{
//! x coordinate
double x;
//! y coordinate
double y;
//! z coordinate
double z;
DPoint3d() = default;
DPoint3d(const DPoint3d&& pt)
{
x = pt.x;
y = pt.y;
z = pt.z;
}
};
int main()
{
//不会调用到移动构造函数,但c里的值被成功赋值过去了。
DPoint3d b;
b.x = 10;
DPoint3d&& c = std::move(b);
//会调用到移动构造函数
DPoint3d b;
b.x = 10;
DPoint3d c = std::move(b);
//不会调用到移动构造函数
DPoint3d&& a = fun();
std::cout << a.x << endl;
}
添加更多的构造函数,还是不会调用到,为什么呢,终于明白,这个地方的c变量,其实就是一个右值引用,属于一个别名。执行之后,c就变成了一个左值,给c的y值赋值,发现b的y值也变了。
那其实这种情况下,DPoint3d&& c = std::move(b);的效果和DPoint3d& c = b;没什么区别了
struct DPoint3d
{
//! x coordinate
double x;
//! y coordinate
double y;
//! z coordinate
double z;
DPoint3d() = default;
DPoint3d(const DPoint3d& pt)
{
std::cout << "123" << endl;
x = pt.x;
y = pt.y;
z = pt.z;
}
DPoint3d(const DPoint3d&& pt)
{
std::cout << "456" << endl;
x = pt.x;
y = pt.y;
z = pt.z;
}
DPoint3d& operator=(DPoint3d&& pt) {
std::cout << "789" << endl;
x = pt.x;
y = pt.y;
z = pt.z;
}
};
int main()
{
DPoint3d b;
b.x = 10;
DPoint3d&& c = std::move(b);
c.y = 20;
}
DPoint3d&& fun()
{
DPoint3d a; // 默认构造
a.x = 1;
a.y = 2;
a.z = 3;
// return a; // 报错:无法将左值绑定到右值引用
//return std::move(a); // 返回右值引用,没有进行构造
return a; // 返回右值引用,没有进行构造
}
编译错误:
error C2440: “return”: 无法从“DPoint3d”转换为“DPoint3d &&”
note: 无法将左值绑定到右值引用
改一下fun函数,直接返回一个对象,发现调用了DPoint3d(const DPoint3d&& pt);,外面的右值引用变量c也能正常使用,而且出了作用域之后,c立刻被释放了,析构函数被调用:
struct DPoint3d
{
//! x coordinate
double x;
//! y coordinate
double y;
//! z coordinate
double z;
DPoint3d() = default;
~DPoint3d()
{
std::cout << "~DPoint3d" << endl;
}
DPoint3d(const DPoint3d& pt)
{
std::cout << "123" << endl;
x = pt.x;
y = pt.y;
z = pt.z;
}
DPoint3d(const DPoint3d&& pt)
{
std::cout << "456" << endl;
x = pt.x;
y = pt.y;
z = pt.z;
}
DPoint3d& operator=(DPoint3d&& pt) {
std::cout << "789" << endl;
x = pt.x;
y = pt.y;
z = pt.z;
}
};
DPoint3d fun()
{
DPoint3d a; // 默认构造
a.x = 1;
a.y = 2;
a.z = 3;
// return a; // 报错:无法将左值绑定到右值引用
//return std::move(a); // 返回右值引用,没有进行构造
return a; // 返回右值引用,没有进行构造
}
int main()
{
DPoint3d&& c = fun();//DPoint3d c = fun();效果一样
std::cout << c.x << endl;
int i = 0;
++i;
}