在c++右值引用之转移构造函数文章中,我们介绍了移动构造函数三点注意问题
1、参数(右值)的符号必须是右值引用符号,即“&&”。
2、参数(右值)不可以是常量,因为我们需要修改右值。
3、 参数(右值)的资源链接和标记必须修改。否则,右值的析构函数就会释放资源。转移到新对象的资源也就无效了。
关于第三点原因:虽然调用移动构造函数或者移动赋值操作符后,已经获得了右值的的内存空间,但是之后右值就被销毁了,那么获得的的那片内存也被释放了,指向的就是一个不合法的内存空间。所以我们就要防止这片空间被销毁。
下面有三个问题:
1、没有拷贝构造函数会默认生成移动构造函数吗?
2、有拷贝构造函数还会默认生成移动构造函数吗?
3、有移动构造函数还会默认生成拷贝构造函数吗?
首先看一下代码,简单写了一个类:
#include <iostream>
using namespace std;
class A {
public:
A(int *ptr = new int) :p(ptr) {}
/*A(A &a) :p(a.p)
{
cout << "调用了拷贝构造函数" << endl;
}*/
//A(A &&a) :p(a.p)//本人猜测合成的移动构造函数只完成这一步,而函数体是空的
//{
一定要修改指针的指向,这样移动构造就不会析构原对象的成员了
// a.p = nullptr;
// cout << "调用了移动构造函数呀" << endl;
//}
int *p;
};
int main()
{
//A a1(new int(4));
A a1;
A a3;
A a2(std::move(a1));
A a4(a3);
cout << a1.p << endl;
cout << a3.p << endl;
system("pause");
return 0;
}
1、没有拷贝构造函数会默认生成移动构造函数吗?
看编译结果可知,编译器会自动生成拷贝构造函数和移动构造函数。
但是在默认生成移动构造函数时,未将指针指向NULL,这就有可能出现问题。
默认的移动构造函数不会帮我们把指针成员置空,移后源不是可析构的安全状态,如果这样,当离开移动构造后,源对象被析构,对象内的指针成员空间被回收,转移之后对象内的指针成员出现悬垂现象,程序将引起致命的错误。所以当我们定义了自己的拷贝操作和析构函数时,编译器是不会帮我们合成默认移动构造函数的。这也回答了下一个问题。
2、有拷贝构造函数还会默认生成移动构造函数吗?
把上述代码解除拷贝构造函数的注释就行。
3、有移动构造函数还会默认生成拷贝构造函数吗?
把上述代码解除移动构造函数的注释就行。
具体原因还没有查清,望大佬赐教!
也可参考C++Error2208:…尝试引用已删除的函数这篇文章。
一般而言,对象的赋值构造函数如果开发者没有提供,则编译器会生成默认的赋值构造函数。然而,默认的赋值构造函数在以下几种情况会被删除。
该类含有非静态的const成员变量
该类含有非静态的reference成员变量
该类含有不能被拷贝的成员变量
该类含有不能被拷贝的基类
该类含有用户定义的移动构造函数或者移动赋值函数
自己编写的类中有const成员变量, 将其改成static 或者去掉const 或者添加赋值构造函数,就可以消除这个error.