struct DPoint3d
{
//! x coordinate
double x;
//! y coordinate
double y;
//! z coordinate
double z;
int*p = nullptr;
DPoint3d()
{
p = new int(5);
std::cout << "DPoint3d" << endl;
}
DPoint3d(double _x, double _y, double _z)
{
p = new int(5);
x = _x;
y = _y;
z = _z;
}
~DPoint3d()
{
delete p;
p = nullptr;
std::cout << this << endl;
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&& fun1()
{
return DPoint3d{1,2,3}; //warning C4172: 返回局部变量或临时变量的地址。
注意“地址”这个词。说明DPoint3d&&代表了一种指针?
}
int main()
{
{
DPoint3d&& a = fun1();
a.y = 20;
std::cout << &a << endl;//一取地址,就露馅了
int i = 0;
++i;
}
a接到的对象已析构。错误用法。
所以,fun1就是返回了一个局部匿名对象的指针,但局部对象该析构还是析构。
所以,返回的就是指向这个局部匿名对象的指针,但返回的时候已经释放了,
所以指向了一块已经释放了的对象,自然会引发未定义行为。
DPoint3d&& fun1()
{
return DPoint3d{1,2,3}; //warning C4172: 返回局部变量或临时变量的地址。
注意“地址”这个词。说明DPoint3d&&代表了一种指针?
}
int main()
{
{
DPoint3d a = fun1();
a.y = 20;
std::cout << &a << endl;//一取地址,就露馅了
int i = 0;
++i;
}
fun1在返回之前已经析构,但程序用析构的对象去初始化变量a,
但此时fun1里的那个析构的函数里的数据已经是无效值了。
a再去接这些数据,会导致未知行为。
错误用法。
所以,在函数的定义的角度,以下做法就是错误的:函数内部的局部变量,返回值类型是DPoint3d&&。不管提没提供移动构造函数。不管在外面是否用右值DPoint3d&&来接。
分析来看,右值引用&&,有点像一种指针,一种比引用&更牛逼一些的指针,因为引用只能引用左值,而右值引用可以直接引用右值,也可以通过std::move(左值)的方式进行引用。
为什么说右值引用像一种指针呢,看下面这个例子,编译器给出的警告信息内容:
int&& fun2()
{
return 1; //注意这个提示: warning C4172: 返回局部变量或临时变量的地址。
注意“地址”这个词。说明DPoint3d&&代表了一种指针?
}
{
int&& a = fun2();
std::cout << &a << endl; //一取地址,a值就变了,随机值,比如3271
int i = 0;
++i;
}
编译器提示:warning C4172: 返回局部变量或临时变量的地址
注意,说是返回了。。。的“地址”
返回值刚出来,可能编译器没刷新,还显示的是1:
取地址后,a的值露出原形:
int&& fun2()
{
return 1; // 默认构造
}
int main()
{
{
int a = fun2();
std::cout << &a << endl;
int i = 0;
++i;
}
这个倒是对了,起码函数返回的瞬间把值给复制给了a。
毕竟是pod类型的数据。但尽量别这么用
看其他博客,都说右值可以延长变量的生命期,是不是这种情况,以右值是一种指针的方向理解一下:
DPoint3d fun1()
{
return DPoint3d{1,2,3}; // 默认构造
}
{
DPoint3d&& a = fun1();
a.y = 20;
std::cout << &a << endl;
int i = 0;
++i;
}
这种情况下,不会调用到DPoint3d的任何构造函数(包括移动构造函数)
自始至终就是一个对象,如果打印对象地址,发现是一样的:
000000FA1D37DD78 构造的时候
000000FA1D37DD78 std::cout << &a << endl;的时候
000000FA1D37DD78 执行完++i;后析构的时候
~DPoint3d
DPoint3d fun1()
{
return DPoint3d{1,2,3}; // 默认构造
}
{
DPoint3d&& a = fun1();
a.y = 20;
std::cout << &a << endl;
int i = 0;
++i;
}
这种情况下,不会调用到DPoint3d的任何构造函数(包括移动构造函数)
可能是进行了返回值优化
自始至终就是一个对象,如果打印对象地址,发现是一样的:
000000AB5B92DA78 构造的时候
000000AB5B92DA78 std::cout << &a << endl;的时候
000000AB5B92DA78 执行完++i;后析构的时候
~DPoint3d