先看个例子:
vector<string> v1(1000000);//v1存放着100W个string,假设每个string长度为1000
vector<string> v2=copyVector(v1);//使用v1初始化v2
构造v2的时候,编译器先利用v1构造生成了一个temp副本,然后将temp复制给一个临时对象,返回给v2,v2利用该临时对象,构造自己。这将导致非常巨大的工作量!做了大量的无用功(将temp复制给一个临时对象,返回给v2,v2利用该临时对象,构造自己)。在这之后,temp这个临时的对象被删除了,返回的那个temp副本临时对象也被删除了,如果编译器能够将temp的所有权直接转移给v2不是更好吗?也就是说,不用将100W个string多次复制到新的地方,再删除原来的字符,而是直接保留字符,并将v2与之关联。这类似于计算机中文件的移动。实际文件还保留在原来的地方,而只是记录修改了,这种方法称之为移动语义。
移动语义避免了移动原始数据,而只是修改了记录。
要实现移动语义,必须让编译器知道什么时候需要复制,什么时候不需要复制。这就是右值引用发挥最大作用的地方。
移动语义程序
#include <iostream>
using namespace std;
class A {
private:
int data;//data
int *pi;//point to data
public:
//禁止隐式转换
A() {
}
explicit A(int i) :data(i) {
cout << "normal constuctor1!" << endl;
pi = &data;
}
A(const A &a) {
data = a.data;
cout << "copy constructor!" << endl;
pi = &data;
}
A(A &&a) {
cout << "move constructor!" << endl;
//直接移动a.pi到pi
pi = a.pi;
data = a.data;
//修改源pi
a.pi = nullptr;
a.data = 0;
}
//A(A &&a)=delete;
A operator+(const A &a) {
A temp(data + a.data);
cout << endl << "operator+ called!show temp!" << endl;
temp.show();
cout << endl;
return temp;
}
void show()const {
cout << "pi=" << pi << " data=" << data << endl;
}
};
int main() {
int i = 99;
A a(10);
a.show();
A b(i);
b.show();
A c(b);
c.show();
b + c;
// A d(b + c);
cout << "show d!" << endl;
// d.show();
}
结果:
如果修改函数A operator+(const A &a)为以下代码:
void operator+(const A &a) {
A temp(data + a.data);
cout << endl << "operator+ called!show temp!" << endl;
temp.show();
cout << endl;
//return temp;
}
则出现以下结果:
调试分析代码可知,在return temp;这一句执行之前将要调用A(A&&)这个构造函数。
使用拷贝构造函数和移动构造函数的区别:
(1)使用深层拷贝构造函数
返回时构造临时对象,动态分配临时对象返回到主调函数,然后删除临时对象。
(2)使用移动构造函数
将要返回的局部对象转移到主调函数,省去了构造和删除临时对象的过过程。
如果将函数A operator+(const A &a)注释掉,会出现如下结果:
参考博客:http://blog.csdn.net/niteip/article/details/37814483