c++ 深度拷贝和浅拷贝

本文通过实例介绍了C++中深拷贝和浅拷贝的概念及区别,强调了浅拷贝可能导致的析构时内存释放问题,并展示了如何通过自定义深拷贝构造函数来解决这个问题。在示例中,作者创建了一个包含动态分配内存的对象,并展示了在浅拷贝和深拷贝情况下,对象内存管理的不同情况。
摘要由CSDN通过智能技术生成

一、简介

由于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

结论: 

使用才会精进,一旦不使用,最简单的问题也会被遗忘 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值