复制
浅层复制和深层复制
浅层复制
浅层复制只实现对象间的数据元素一一对应,只复制成员函数中的指针地址,如下图:pointArray2复制了pointArray1,只复制了指针,pointArray2与pointArray1指向了同一块数组元素,在运行后进行内存释放时会先调用pointArray1的析构函数释放数组内存,而当pointArray2调用析构函数释放数组内存时会出错,因为此时这块内存已经被释放,不存在了。
因此浅层复制不能用来返回含有指针成员的对象
深层复制
当被复制的对象数据成员是指针类型时,不是复制该指针成员本身,而是将指针所指向的对象进行复制。
ArrayOfPoints::ArrayOfPoints(const ArrayOfPoints &v) {//复制构造函数,实现深层复制
size = v.size();
points=new Point[size];
for(int i=0;i<size;i++)
points[i]=v.points[i];
}
通过编写复制构造函数将指针指向数组中的元素进行一一复制,从而实现深层复制
移动构造
深层复制,是将含有指针的成员函数连带指针所指向的区域一起复制一份,但有时,我们存在复制之后,原先的对象不再用到的情况,这样就导致了内存空间的浪费,因此有了移动构造(我也将其理解为剪切)。
c++11之前,如果要将源对象的状态转移到目标对象,只能通过复制。但c++11有了移动构造,此时,转移只需要移动对象即可。注意:移动构造时必须要把源对象资源的所有控制权都交给目标对象。
移动构造通过移动构造函数实现:如:class_name(class_name && )
//使用深层复制的方式返回临时对象(主函数中调用一个函数,函数自己创建一个类后返回这个类,主函数再调用这个类中的方法)
#include<iostream>
using namespace std;
class IntNum{
public:
IntNum(int x=0):ptr(new int(x)){
cout<<"calling constructor..."<<endl;
}
IntNum(const IntNum &n):ptr(new int(*n.ptr)){
cout<<"calling copy constructor..."<<endl;
}
~IntNum(){
delete ptr;
cout<<"destory..."<<endl;
}
int getInt(){
return *ptr;
}
private:
int *ptr;
};
IntNum getNum(){
IntNum a;
return a;
}
int main(){
cout<<getNum().getInt()<<endl;
return 0;
}
//移动构造的形式实现对象的返回(由于a这个对象迟早要消亡,不如直接转移出a对象中的内容)
#include<iostream>
using namespace std;
class IntNum{
public:
IntNum(int x=0):ptr(new int(x)){
cout<<"calling constructor..."<<endl;
}
IntNum(const IntNum & n):ptr(new int(*n.ptr)){
cout<<"calling copy constructor..."<<endl;
}
IntNum(IntNum && n):ptr(n.ptr){ //移动构造函数,将形参的指针直接赋给当前对象的指针(浅层复制)
n.ptr = nullptr;//将源对象的指针变成空指针来达到移动构造
cout<<"calling move constructor..."<<endl;
}
~IntNum(){
delete ptr;
cout<<"destory..."<<endl;
}
int getInt(){
return *ptr;
}
private:
int *ptr;
};
IntNum getNum(){
IntNum a;
return a;
}
int main(){
cout<<getNum().getInt()<<endl;
return 0;
}
由上可知,可以通过深层复制和移动构造的方式将函数中含有指针的对象返回。
使用深层复制构造函数时,返回时构造临时对象,动态分配后将临时对象返回给主调函数,最后删除临时对象。
使用移动构造函数时,将要返回的局部变量直接转移到主函数。省去了构造和删除临时对象的过程。