深度拷贝与浅拷贝

#include<string>
#include<iostream>
using namespace std;
class DeepCopy
{
public:
	DeepCopy()
	{
	cout<<"invoke default constructor"<<endl;
	}
	DeepCopy(string name)
	{
		this->name = name;
		cout<<"invoke normal constructor"<<endl;
	}
	~DeepCopy()
	{}
private:
	string name;
};

#include"deepCopy.h"
using namespace std;
int main()
{
	DeepCopy a("hello");
	DeepCopy b;
	b=a;
	return 0;
}

   在C++中,对象实例在编译的过程中,就会为其在stack上分配内存,同时返回一个指向对应地址空间的reference。(ps:new 声明的空间会分配在heap上,必须delete,不然会耗尽内存”)。下面我们简单介绍一下拷贝运算与赋值运算的使用场景以及区别。

当对象在声明的时候马上进行初始化,则称为拷贝运算。如:

DeepCopy a("hello");

当对象在声明之后,进行赋值运算,称之为赋值运算。如:

DeepCopy b;

深度拷贝与浅拷贝_第1张图片

b=a;

    此时由于没有重新定义赋值运算,所以调用了系统默认生成的赋值函数。该赋值运算的原理是默认只拷贝位于stack中的值,对于heap上的值不会进行拷贝,只会指向同一个空间。(浅拷贝)

深度拷贝与浅拷贝_第2张图片

Tip:这样做还有一个坏处,当调用析构函数时,会两次删除heap上同一块空间,这样会报错。


为了解决浅拷贝的问题,我们需要在进行赋值运算的时候,对heap空间的内容同样进行拷贝,为其分配一个单独的内存空间,解决方案是:赋值运算符重载(深拷贝)。

Tips:只有在用到new 分配heap上空间时才需要深度拷贝!同时重写拷贝构造函数与赋值函数,针对heap空间单独分配。

    DeepCopy& operator =( DeepCopy& a) //注意:此处一定要返回对象的引用,否则返回后其值立即消失!
    {
        if(name!=NULL)														//删除原heap分配的空间,如果有的话
                delete name;
        int len=strlen(a.name);
        name=new char[len+1];											//分配新的heap空间
        strcpy(name,a.name);
        return *this;
    }
    	DeepCopy(char* name)
	{
	    this-> name=new char[strlen(name)+1];
	    strcpy(name,name);
		cout<<"invoke normal constructor"<<endl;
	}

深度拷贝与浅拷贝_第3张图片

如果类内部有指向heap空间的指针,请一定要使用引用传递值,而不是简单使用值传递参数。对比如下:

DeepCopy& operator =( DeepCopy& a)
//注意:此处一定要返回对象的引用,否则返回后其值立即消失!
    {
        if(name!=NULL)														//删除原heap分配的空间,如果有的话
                delete name;
        int len=strlen(a.name);
        name=new char[len+1];											//分配新的heap空间
        strcpy(name,a.name);
        return *this;
    }
    
    	DeepCopy dc1("hello");
	DeepCopy dc2;
	dc2=dc1;

调用赋值函数时所经历的过程:

  1. 释放原来对象的堆空间

  2. 重新申请对应的堆空间

  3. 拷贝源堆空间的值到当前堆空间

  4. 返回对象的引用

但是如果函数返回的是值而不是对象的引用时,这时候由于没有进行深度拷贝,在析构临时变量的时候会删除heap空间内的内容会报错。(这个地方还不是特别清楚,我会持续更新的)

  

你可能感兴趣的:(深度拷贝与浅拷贝)