C++-Record21—浅拷贝及深拷贝问题

半腔热情 提交于 2020-01-21 23:58:47

目录

浅拷贝问题抛出

浅拷贝问题的分析

浅拷贝问题的解决方案

默认等号操作符执行赋值操作时也是浅拷贝

总体代码


浅拷贝问题抛出

先看一段代码,定义一个Name类,类里面,手工定义的一个构造函数贺析构函数,没有定义拷贝函数:

class  Name
{
public:
	Name(const char *myp)
	{
		m_len = strlen(myp);
		m_p =(char *) malloc(m_len + 1); //
		strcpy(m_p, myp);
	}

	//Name obj2 = obj1;

	~Name()
	{
		if (m_p != NULL)
		{
			free(m_p);
			m_p = NULL;
			m_len = 0;
		}
	}
protected:
private:
	char *m_p ;
	int m_len; 
};

 开始进行调用,会发现中间这步"Name obj2 = obj1;"是需要调用拷贝构造函数的,但类中并没有手动定义,所以,调用的是编译器自动匹配的拷贝构造函数。

void objplaymain()
{
	Name obj1("abcdefg");
	Name obj2 = obj1;  //C++编译器提供的 默认的copy构造函数  浅拷贝
}

void main91()
{
	objplaymain();
	cout<<"hello..."<<endl;
	system("pause");
	return ;
}

但是,这个代码是无法运行的,无法运行的原因就是,因为编译器自动设置的拷贝构造函数出现了问题。

补充:

在上面的代码中,弄不清楚字符串是怎么拷贝的,回翻看:

"C语言指针"专栏的"Record12—字符串1级指针的内存模型",这里有关于字符串的详细叙述。

https://blog.csdn.net/qq_17846375/article/details/103679709

定义函数:char *strcpy(char *dest, const char *src);

函数说明:strcpy()会将参数src 字符串拷贝至参数dest 所指的地址。

返回值:返回参数dest 的字符串起始地址。

浅拷贝问题的分析

延续上面出现的问题,本节进行分析,将上面的过程的内存四区图画出来:

C++编译器执行默认的拷贝构造函数,执行的是一个浅拷贝,即把对象obj1的属性(m_p,m_len),复制一份放到同样的内存区中,只是把指针变量的值和变量的值复制一份给obj2,没有把指针变量所指向的内存空间给重新开辟内存。这种拷贝只是把值给拷贝了, 没有把指针变量指向内存空间的数据也给拷贝了,这种拷贝就叫浅拷贝。所新生成的obj2,里的指针变量指向的内存空间还是原来的内存空间。当析构的时候,先析构obj2,再析构obj1,可因为析构obj2时候,把指向的内存空间给清除了,等到obj1析构的时候,提示原来的内存空间已经释放掉了,肯定不能重复释放了,所以,就报错了!

浅拷贝问题的解决方案

浅拷贝的问题一句话来概括就是两个指针变量指向同一块内存空间造成的错误。那么如何解决呢?这种情况,我们应该使用深拷贝。应该在生成新的指针变量的时候,同时生成新的指针变量所指向的内存空间。

写深拷贝的拷贝构造函数:

	//解决方案: 手工的编写拷贝构造函数 使用深copy
	Name(const Name& obj1)
	{
		m_len = obj1.m_len;
		m_p = (char *)malloc(m_len + 1);
		strcpy(m_p, obj1.m_p);
	}

这样的就是深拷贝了。

默认等号操作符执行赋值操作时也是浅拷贝

//对象析构的时候 出现coredump
void objplaymain()
{
	Name obj3("obj3");

	obj3 = obj1;  // C++编译器提供的 等号操作 也属 浅拷贝
}

 这也是一个浅拷贝,也会出现两个指针指向同一块儿内存空间,造成报错。想解决这种问题,我们必须显式的重载等号运算符才可以,至于具体的怎么做,这里制作抛砖,以后引玉。

这里简单叙述一下原理:

当新开一个obj3的时候,里面的指针变量存放的是一个不同于obj1指向的新的内存空间,而当用等号进行赋值操作的时候,就把obj3中指针变量存放的指针粗暴的改成了obj1中对应的值,即将obj1和obj3中的指针变量都指向了同一块的内存空间,而原理被obj3指向的空间,就被弄丢了,造成内存空间泄漏。 

总体代码

dm09_深拷贝和浅拷贝.cpp


#define  _CRT_SECURE_NO_WARNINGS 
#include <iostream>
using namespace std;

//

class  Name
{
public:
	Name(const char *myp)
	{
		m_len = strlen(myp);
		m_p =(char *) malloc(m_len + 1); //
		strcpy(m_p, myp);
	}

	//Name obj2 = obj1;
	//解决方案: 手工的编写拷贝构造函数 使用深copy
	Name(const Name& obj1)
	{
		m_len = obj1.m_len;
		m_p = (char *)malloc(m_len + 1);
		strcpy(m_p, obj1.m_p);
	}

	~Name()
	{
		if (m_p != NULL)
		{
			free(m_p);
			m_p = NULL;
			m_len = 0;
		}
	}
protected:
private:
	char *m_p ;
	int m_len; 
};

//对象析构的时候 出现coredump
void objplaymain()
{
	Name obj1("abcdefg");
	//Name obj2 = obj1;  //C++编译器提供的 默认的copy构造函数  浅拷贝
	Name obj3("obj3");

	obj3 = obj1;  // C++编译器提供的 等号操作 也属 浅拷贝
}

void main91()
{
	objplaymain();
	cout<<"hello..."<<endl;
	system("pause");
	return ;
}

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!