C++中浅拷贝与深拷贝
文章目录
1.概念
(1)浅拷贝
简单来说,浅拷贝就是同一个类中不同的类对象中的成员指针变量,指向了同一块堆内存。打个比方来说就像两个人穿了同一条裤子。
(2)示意图
(3)出现浅拷贝的原因
在类中,若我们不去定义拷贝构造函数,则编译器会自动生成默认拷贝构造函数。若在类中,有一个公有的指针类型的属性成员,我们通过类实例化第一个对象,然后通过默认拷贝构造函数利用第一个示例话对象的副本去创建第二个对象。当调用我们自定义的析构函数释放勒种的指针类型的属性成员时,编译器并不会顺利的执行。
2.浅拷贝测试示例
(1)示例代码
#include <iostream>
using namespace std;
class CBase
{
string m_sName;
int *m_nAge;
public:
CBase()
{
m_nAge = nullptr;
}
CBase(const char *name, int age)
{
m_sName = name;
m_nAge = new int(age);
}
~CBase()
{
delete m_nAge;
}
void Print()
{
cout << m_sName.c_str() << " 的年龄为 "
<< m_nAge << endl;
}
};
int main()
{
CBase c1("lisa", 18);
CBase c2(c1);
c1.Print();
c2.Print();
return 0;
}
(2)程序运行结果
- 通过编译器默认拷贝构造函数完成拷贝构造后,地址如下;
- 调用类成员函数Print打印输出;
- C2对象进行析构,正常完成析构过程;
- C1对象进行析构时就出现了错误,程序被编译器中断。
(3)结论
程序出现中断,是因为C2和C1对象进行构造时,类内的指针变量指向了同一块堆内存地址,所以析构了一次后,再次对已经析构的地址进行析构就会出错,也就是说浅拷贝存在堆内存冲突问题。
3.如何解决浅拷贝问题
(1)使用深拷贝
深拷贝就是指对象间进行拷贝构造时,对需要构造的对象的指针变量进行堆空间申请,然后再进行成员赋值。使用深拷贝的方法能很好的解决浅拷贝时内存释放冲突问题。由于编译器默认的拷贝构造函数为浅拷贝,所以我们需要自行新增一个深拷贝的拷贝构造函数。
新增的拷贝构造函数需要两个步骤:
步骤:
1、先对需要拷贝构造的对象中指针变量先申请空间;
2、对申请好空间的指针变量进行赋值。
CBase(const CBase &p)
{
m_sName = p.m_sName;
m_nAge = new int(*p.m_nAge);
}
(2)示例代码
#include <iostream>
using namespace std;
class CBase
{
string m_sName;
int *m_nAge;
public:
CBase()
{
m_nAge = nullptr;
}
CBase(const char *name, int age)
{
m_sName = name;
m_nAge = new int(age);
}
CBase(const CBase &p)
{
m_sName = p.m_sName;
m_nAge = new int(*p.m_nAge);
}
~CBase()
{
delete m_nAge;
}
void Print()
{
cout << m_sName.c_str() << " 的年龄为 " << *m_nAge << endl;
}
};
int main()
{
CBase c1("lisa", 18);
CBase c2(c1);
c1.Print();
c2.Print();
return 0;
}
(3)运行结果
- 内存示意
- 运行结果
- 正确释放内存,解决了浅拷贝中释放内存冲突的问题。
4、什么时候使用浅拷贝,什么时候使用深拷贝
对于类中没有成员指针变量需要申请内存,直接使用浅拷贝即可;而对于类内有指针变量需要申请堆内存时,使用深拷贝。