c++11 引入了左值,右值,移动构造函数,移动赋值函数等新概念,其实都是为了支持移动语义而引入的
c++11引入了左值和右值的概念:
- 左值:能取使用&获取到地址的都为左值
- 右值:不能获取地址的为右值,匿名变量一律为右值
- std::move()函数将左值转化成右值
- 右值引用主要用于移动语义(move)和完美转发
移动构造函数的功能:
1.移动构造函数一般是在类中需要深拷贝(即成员变量含有指针类型,内容存放在堆中)的时候才需要用,移动构造函数的功能跟拷贝构造函数的功能类似,有一点不同的是,在拷贝构造函数中实现深拷贝的内容,在移动构造函数中直接把原对象的指针直接赋值给新的对象(没有重新在堆中申请内存然后把原对象的内容拷贝过来,而是直接使用原对象的内存地址),然后将原对象的指针置为NULL(避免在原对象析构时把这段内容释放掉,delete NULL这样的操作也不会出问题)
2.移动构造函数优先规则:当类中同时包含移动构造函数和拷贝构造函数时,如果使用临时对象初始化当前类的对象,编译器会优先使用移动构造函数来完成此操作。只有当类中没有移动构造函数时,才会选择拷贝构造函数来完成。
3.如果使用左值来构造新的对象,但是又想调用移动构造函数来完成,那么就可以使用std::move()函数来将左值转化成右值,然后编译器就会选择移动构造函数来完成这个拷贝操作
下面是示例代码
#include <iostream>
#include <vector>
#include <set>
#include <string>
#include <algorithm>
#include <map>
#include <unordered_map>
#include <queue>
#include <list>
#include <stack>
using namespace std;
class A {
public:
A(int i, std::string str):i(i){
len = str.size() + 1;
p = new char[len]{ 0 };
memcpy(p, str.c_str(), str.size());
cout << "construct" << endl;
}
A() = default;
A(const A& a)//拷贝构造函数(深拷贝)
:p(new char[len])
{
memcpy(p, a.p, len);
len = a.len;
cout << "copy construct" << endl;
}
A(A &&a)//移动构造函数
{
i = a.i;
p = a.p;
len = a.len;
a.len = 0;
a.p = NULL;//然后再将指针置为NULL
cout << "move construct" << endl;
}
~A()
{
delete p;
cout << "destruct" << endl;
}
public:
int i = 0;
int len = 0;
char *p = NULL;
};
int main(int argc, char** argv)
{
A a(4, "hahahh");
printf("a.p=%x\n", a.p);
A b(std::move(a)); //通过使用std::move函数将左值a转换成右值,调用移动构造函数
printf("a.i=%d a.p=%x b.i=%d b.p=%x\n", a.i, a.p, b.i, b.p);
A c(b); //b是左值,只能调用拷贝构造函数
return 0;
}
以上程序输出为:
construct
a.p=9cfed40
move construct
a.i=4 a.p=0 b.i=4 b.p=9cfed40
copy construct
destruct
destruct
destruct
参考文章:
http://c.biancheng.net/view/7847.html
https://blog.csdn.net/p942005405/article/details/84644069/