【总结笔记】深浅拷贝与移动构造原理总结
1 浅拷贝与深拷贝的区别
深浅拷贝针对的是动态分配的内存、指针等数据类型的对象而言的拷贝方式。
1.1 浅拷贝
基本类型数据以及简单对象的拷贝就是直接按位复制内存。这种默认的隐式拷贝行为称为浅拷贝,与调用 memcpy() 函数的效果非常类似。
2.1 深拷贝
(1)默认的隐式浅拷贝方式无法拷贝 动态分配的内存、指向其他数据的指针等,只能依赖显式的深拷贝方式。
(2)深拷贝会为会将原有对象的所有成员变量(包括指针)拷贝给新对象 同时为新对象分配一块内存(指针指向的内容),并将原有对象所持有的内存也拷贝过来。此时原有对象与新对象就是相互独立的。
3 移动构造函数
移动构造函数最开始解决的是临时对象多次深拷贝的高消耗问题。
demo(const demo &d):num(new int(*d.num)){
cout<<"copy construct!"<<endl;
}
demo get_demo(){
return demo();
}
int main(){
demo a = get_demo();
return 0;
}
如上述例子,demo()
生成的对象被 return
,返回对象要调用 1 次(深)拷贝函数,demo a = get_demo();
执行赋值,也要执行 1 次(深)拷贝。由于 2 个临时对象生命周期非常短,因此没比要花费如此大的开销进行 2 次深拷贝。移动构造函数就是改变 动态分配的内存 及 指针的生命周期,将新对象的指针指向原对象,并将原对象的指针置空。
demo(demo &&d):num(d.num){
d.num = NULL;
cout<<"move construct!"<<endl;
}
移动构造函数使用右值引用形式的参数。程序执行结果中产生的临时对象既无名称也无法获取其存储地址,所以属于右值。即:当类中同时包含拷贝构造函数和移动构造函数时,如果使用临时对象初始化当前类的对象,编译器会优先调用移动构造函数来完成此操作。只有当类中没有合适的移动构造函数时,编译器才会退而求其次,调用拷贝构造函数。
4 move()函数
默认情况下,左值初始化同类对象只能通过拷贝构造函数完成,如果想调用移动构造函数,则必须使用右值进行初始化。但使用std::move() 函数可以将左值强制转换成对应的右值,由此便可以使用移动构造函数。
movedemo demo;
movedemo demo3 = std::move(demo);
//此时 demo.num = NULL,因此下面代码会报运行时错误
//cout << *demo.num << endl;