C++11----新引入的默认成员函数
之前学习了C++的六个默认成员函数:构造函数,析构函数,拷贝构造函数,拷贝赋值重载,取地址重载,const 取地址重载。由于C++11引入了右值引用以及万能引用,所以为了更好地适应新的东西,又引入了移动构造函数和移动赋值运算符重载。
这两个函数与之前的不一样,如果我们不写,编译器也不一定会自动生成,接下来让我们看看这两个函数在什么情况下才会自己生成,又做了些什么。
如果没有实现移动构造函数,且没有实现析构函数 、拷贝构造、拷贝赋值重载中的任
意一个。那么编译器会自动生成一个默认移动构造。因为这表示类不需要特殊的资源管理(如动态内存或文件句柄),默认的成员逐个移动是安全的;一旦类自己管理资源(定义了析构或拷贝相关函数),编译器就不会生成默认移动构造,以防止出现浅拷贝导致的资源重复释放或悬空指针问题。
其实也容易理解,我们在什么情况下才需要自己实现析构函数、拷贝构造、拷贝赋值重载呢?默认的析构函数会调用自定义成员变量的析构函数、基类的析构函数(如果有),但是不会主动释放指针资源;默认的拷贝构造,会按字节拷贝所给对象的内置成员变量,调用自定义类型成员变量的拷贝构造,仅拷贝指针值,不分配新内存;默认的赋值重载与默认的拷贝构造所做的事情差不多,逐成员赋值,调用自定义类型成员的赋值运算符,仅复制指针值。
显而易见,需要做指针资源管理的才需要自己手写这三个函数,而且往往一起出现缺一不可,而其他的情况下用默认生成的就足够了。
那么默认的移动构造和移动赋值做了什么呢?
对于内置类型成员会执行逐成员按字节拷贝,自定义类型成员,则需要看这个成员是否实现移动构造, 如果实现了就调用移动构造,没有实现就调用拷贝构造。(移动赋值:对于内置类型成员会执行逐成员按字节拷贝,自定义类型成员,则需要看这个成员是否实现移动赋 值,如果实现了就调用移动赋值,没有实现就调用拷贝赋值。)
验证一下:只写了构造函数,可以使用移动构造函数。
如果我不给string写移动构造:可以看出来确实是调用了string的拷贝构造
如果写了析构函数呢?只能调用Person的默认拷贝构造了。
但是可以使用default关键字使其强制生成:
又比如说,虽然编译器可以生成默认移动构造,但是我就不让他生成:这里为什么会报错呢,我们知道当表达式是右值时,编译器优先选择移动构造,其次拷贝构造函数;如果移动构造函数被 delete
,编译器不会退回到拷贝构造函数,
我们可以自己写一下移动构造和移动赋值:
调用链条: