深浅拷贝 面试经典问题,也是常见的坑(黑马视频中点到)
浅拷贝 :简单的赋值拷贝操作 编译器提供的
深拷贝 :在堆区重新申请空间,进行拷贝操作
先来试一下怎么做,首先先创建一个类,然后写入无参构造函数,析构函数,再写入有参构造函数和拷贝构造函数
class Person
{
public:
//1.构造函数 进行初始化操作 这些是普通构造
Person()
{
cout << "Person无参构造函数的调用" << endl;//如果没有自己构造,系统自己也会构造
}
~Person()
{
//析构代码,将堆区开辟数据做释放操作
if (m_Height != NULL) //判断指针是否为空
{
delete m_Height;//手动删除
m_Height = NULL;
}
cout << "Person析构函数的调用" << endl;
}
Person(int a , int height)//有参构造函数
{
//将传入的人身上的所有属性,拷贝到新的身上
age = a;
m_Height = new int(height);//堆区数据需要程序员手动释放
cout << "Person有参构造函数的调用" << endl;//如果没有自己构造,系统自己也会构造
}
//拷贝构造函数的调用 如果使用编辑器默认的拷贝构造函数就是浅拷贝操作
Person(const Person& p)
{
cout << "拷贝构造函数的调用" << endl;
age = p.age;
m_Height = p.m_Height;//编辑器默认实现的是这行代码
}
int age;
int* m_Height;//身高开辟到堆区
};
这时写一个test代码
void test01()
{
Person p1(18 ,160);
cout << "p1的年龄" << p1.age <<"身高为"<<*p1.m_Height << endl;
Person p2(p1);
cout << "p2的年龄" << p2.age << "身高为" << *p2.m_Height << endl;
}
//调用测试代码
int main()
{
test01();
system("pause");
return 0 ;
}
在test运行完之后,执行析构的代码,如果没有使用深拷贝操作而使用系统默认的浅拷贝操作会发生错误,原因是int* m_Height是一个指针,指向的是堆区的数据,如果对它进行浅拷贝操作,会将这个地址传给p2,也就是说p2.m_Height的指针也会指向同一个堆区的地址,两个地址相同,当第一个执行到析构的时候,先删除了这个内存,那么第二个调用析构的时候内存为空,这也就是为什么会出现错误的原因了(这里栈有个规则,就是先进后出,所以P2会先被释放)
浅拷贝带来的问题就是堆区的内容重复释放。
这时候要使用深拷贝来解决浅拷贝带来的问题,自己构造一个深拷贝的拷贝构造函数,主要是再在堆区开辟一个新的空间存放相同的数据,这样指针就不会交叉释放了。
Person(const Person& p)
{
cout << "拷贝构造函数的调用" << endl;
age = p.age;
//m_Height = p.m_Height;编辑器默认实现的是这行代码
//深拷贝操作
m_Height = new int(*p.m_Height);
}
结论:如果属性有在堆区开辟的,一定要自己提供拷贝构造函数,防止浅拷贝带来的问题
又得开始跑实验咯