一、简介
由于20年转行之后一直用的是halcon 和c# ,C++就此搁浅,最近开始搞pcl慢慢的又重拾起来,对于深拷贝和浅拷贝我知道是什么原因造成的,也知道如何解决,但是突然被人问得时候又有点蒙蔽,因此做一个简单的总结。
先看浅拷贝和深拷贝的区别:
浅拷贝:进行简单的赋值拷贝运算,地址是一样的
深拷贝:new 出来的,在堆区申请了内存空间
二、简单剖析
先举一个例子:作为一个足球迷,真心希望梅西能2022 拿下世界杯,对我们这些没有天赋的普通人来说,天赋比努力要重要100000倍(当你真正的努力过你就知道天赋有多么重要)。
class WorldCupChampion
{
public:
string country;
int* years;
WorldCupChampion();
WorldCupChampion(std::string country, int years);
~WorldCupChampion();
};
WorldCupChampion::WorldCupChampion()
{
cout << "默认构造" << endl;
}
WorldCupChampion::WorldCupChampion(string country, int years)
{
this->country = country;
this->years = new int(years);
cout << "调用有参构造 " << *(this->years) << " " << this->country << endl;
}
WorldCupChampion::~WorldCupChampion()
{
cout << "调用析构函数 " << endl;
if (years != NULL) // 由于year是new 在堆区的所以我们要在程序结束的时候将其delete掉
{
delete years;
years = NULL;
}
}
然后我们在复制一个放到b 里面
void test()
{
WorldCupChampion a("阿根廷", 2022);
cout << *(a.years) << "世界杯冠军是 : " << a.country << endl;
WorldCupChampion b(a);
cout << *(b.years) << "世界杯冠军是 : " << b.country << endl;
}
此时我们进行编译:ok
运行:
我们采用断掉调试,毕竟一切皆地址:
分析一下:我们在 创建一个对象a,然后赋值b ,将a 的所有的东西都复制给b ,但是,包括new 出来的东西,从上面的测试可以看出,我们现在的拷贝years 的地址是一样的,也就是说a 和b 的指针都指向了同一块内存空间。
那么当程序退出的时候我们要析构掉,当a 析构的时候已经将2022 这块内存空间已经析构了,那么当b 再次析构的时候 已经没有这块
内存了,导致程序报错。
浅拷贝结论:
浅拷贝带来的问题得本质是析构函数多长释放堆空间
三、深拷贝
为了解决上面的问题:我们自定义了一个拷贝---深拷贝
模式如下:
WorldCupChampion(const WorldCupChampion& a);
我们需要在这个构造当中重复new 出一片空间来存储year
WorldCupChampion::WorldCupChampion(string country, int years)
{
this->country = country;
this->years = new int(years);
cout << "调用有参构造 " << *(this->years) << " " << this->country << endl;
}
下面我们先看结果:
OK,那我们再次使用断点来看看这次他两的地址是不是一样的:
完整代码:
#if 1
class WorldCupChampion
{
public:
string country;
int* years;
WorldCupChampion();
WorldCupChampion(std::string country, int years);
WorldCupChampion(const WorldCupChampion& a);
~WorldCupChampion();
};
WorldCupChampion::WorldCupChampion()
{
cout << "默认构造" << endl;
}
WorldCupChampion::WorldCupChampion(const WorldCupChampion& a)
{
cout << "深度拷贝" << endl;
this->country = a.country;
this->years = new int(*a.years);
}
WorldCupChampion::WorldCupChampion(string country, int years)
{
this->country = country;
this->years = new int(years);
cout << "调用有参构造 " << *(this->years) << " " << this->country << endl;
}
WorldCupChampion::~WorldCupChampion()
{
cout << "调用析构函数 " << endl;
if (years != NULL) // 由于year是new 在堆区的所以我们要在程序结束的时候将其delete掉
{
delete years;
years = NULL;
}
}
void test()
{
WorldCupChampion a("阿根廷", 2022);
cout << *(a.years) << "世界杯冠军是 : " << a.country << endl;
WorldCupChampion b(a);
cout << *(b.years) << "世界杯冠军是 : " << b.country << endl;
}
int main()
{
test();
return 0;
}
#endif
结论:
使用才会精进,一旦不使用,最简单的问题也会被遗忘