一、何时调用拷贝函数
- 何时会调用拷贝函数?
1、对象在创建时使用其他的对象初始化
Person p(q); //此时复制构造函数被用来创建实例p
Person p = q; //此时复制构造函数被用来在定义实例p时初始化p2、对象作为函数的参数进行值传递时
f(p); //此时p作为函数的参数进行值传递,p入栈时会调用复制构造函数创建一个局部对象,与函数内的局部变量具有相同的作用域
需要注意的是,赋值并不会调用复制构造函数,赋值只是赋值运算符(重载)在起作用
p = q; //此时没有复制构造函数的调用! (记住初始化和赋值的区别)
简单来记的话就是,如果对象在声明的同时将另一个已存在的对象赋给它,就会调用复制构造函数;如果对象已经存在,然后将另一个已存在的对象赋给它,调用的就是赋值运算符(重载)
二、深浅拷贝解析
1、两者区别
1.在未定义显示拷贝构造函数的情况下,系统会调用默认的拷贝函数–即浅拷贝,它能够完成成员的一对一拷贝(逐位复制),当类中数据成员没有指针时,利用浅拷贝完全没问题的;但当数据成员中有指针时,如果采用简单的浅拷贝,那么两个类中的两个指针将会指向同一块地址,当对象快结束时,会调用两次析构器,从而导致指针悬挂现象,所以此时必须使用深拷贝
2.简单来说,带指针用深拷贝,不带指针用浅拷贝
2、用图来解释什么是深浅拷贝
1.无指针的浅拷贝
2.有指针的浅拷贝
3.有指针的深拷贝
3、用代码解释深浅拷贝
1.无指针的浅拷贝
class A
{
public:
A(int _data):data(_data){}
A(){}
private:
int data;
};
int main()
{
A a(5);
A b=a;//浅拷贝
}
解释:b=a;就是浅拷贝,执行完b.data=5;如果对象中没有其他资源(如:堆,文件,系统资源),深浅无差。
2.有指针的浅拷贝(导致内存泄露)
class A
{
public:
A(int _size):size(_size)
{
data=new int[size];
}//给data分配size个内存
A(){}
~A()
{
delete []data;
}//析构时释放资源
private:
int *data;
int size;
};
int main()
{
A a(5);
A b=a;
}
- 这里b=a会造成未定义行为,因为类A中拷贝构造器是编译器生成的,所以b=a执行的是浅拷贝(记住:浅拷贝是对象数据之间的简单赋值)例如:b.size=a.size和b.data=a.data
- 这里b的指针data和a的指针指向了堆上的同一块内存,a和b析构时同一块内存将会被释放两次,其结果是,有未定义的内存将会被泄露或程序奔溃!!!
3.有指针的深拷贝,(解决上面的问题)对象另开辟一块内存
class A
{
public:
A(int _size):size(_size)
{
data=new int[size];
}//给data分配size个内存
A(){}
A(const A&_A):size(_A.size)
{
data=new int[size];
}//深拷贝
~A()
{
delete []data;
}//析构时释放资源
private:
int *data;
int size;
};
int main()
{
A a(5);
A b=a;
}
**以上代码就没有问题了,与浅拷贝区别就是,在自己定义的拷贝函数里另开辟一块内存即深拷贝,