c++ 深度拷贝和浅拷贝

一、简介

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

运行:c++ 深度拷贝和浅拷贝_第1张图片

 我们采用断掉调试,毕竟一切皆地址:

c++ 深度拷贝和浅拷贝_第2张图片

 分析一下:我们在 创建一个对象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;
}

下面我们先看结果:

 c++ 深度拷贝和浅拷贝_第3张图片

OK,那我们再次使用断点来看看这次他两的地址是不是一样的:

c++ 深度拷贝和浅拷贝_第4张图片

 完整代码:

#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

结论: 

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

你可能感兴趣的:(C++,c++,开发语言)