目录
- 什么是浅拷贝?
- 浅拷贝的问题
- 使用深拷贝解决浅拷贝问题
- 结束语
什么是浅拷贝?
如果在一个类中没有人为定义拷贝函数,则系统会提供默认拷贝函数。那么在此默认拷贝函数中主要进行了简单的赋值操作,那这个简单的赋值操作我们一般叫做浅拷贝。
浅拷贝的问题
浅拷贝具体有什么问题,我们先看一个示例,如下所示:
class Student
{
public:Student(const char *name, int Age){pName = (char*)malloc(strlen(name) + 1);strcpy(pName, name);age = Age;}~Student(){cout << "析构函数" <<endl;if (pName != NULL){free(pName);pName = NULL;}}
public:char *pName;int age;
};void test02()
{Student s1("小花", 18);Student s2(s1);cout << "s1 Name=" << s1.pName << " s1 age=" << s1.age << endl;cout << "s2 Name=" << s2.pName << " s2 age=" << s2.age << endl;
}
代码运行结果如下:
如上图所示,代码并不能正常运行,我们接下来分析原因。
Student s1("小花", 18);
首先我们先实例化对象,并且该对象名为s1,在实例化对象过程中会进行如下几步:
- 申请一块内存空间用来存放公有变量pName和age。
- 调用构造函数,在堆中申请一块内存空间,将指针name所指向的内容赋值给刚刚在堆中申请的内存空间,则该空间内容为“小花”
- 将Age赋值给age。
最终如下所示:
Student s2(s1);
当执行这条语句时,会调用拷贝构造函数,但是我们在类中并没有设定拷贝构造,故会调用系统默认的拷贝构造函数,即浅拷贝。即s2.pName = s1.pName,s2.age = s1.age。如下图所示:
此时当执行完test02函数时,会调用s1的析构函数和s2的析构函数。我们接下来分析下:
调用s1的析构函数时,会判断pName指向的空间存不存在,如果存在,即释放掉该空间,并将pName指针指向空。同样的操作,当执行s2的析构函数时,也会判断pName指向的空间存不存在,如果存在,则释放掉该空间,但是此时出现一个问题,pName指向的那块空间在执行s1析构函数时已经释放掉了,即再次释放空间时,会出现错误。这就是浅拷贝的问题,也是上述代码没有正常运行的根本原因(同一块空间被释放两次)。
使用深拷贝解决浅拷贝问题
在之前的示例中因为我们没有人为定义拷贝构造函数,使得自动调用了系统的默认拷贝构造函数,才造成同一块内存空间被同时释放两次的现象。那么为了解决这个问题,我们可以通过自己写拷贝构造函数来解决这个问题。
先上代码:
//深拷贝Student(const Student &stu){cout << "自己的拷贝构造函数" << endl;//1.申请空间pName = (char*)malloc(strlen(stu.pName) + 1);//2.拷贝数据strcpy(pName, stu.pName);age = stu.age;}
运行代码结果如下:
结束语
如果觉得这篇文章还不错的话,记得点赞 ,支持下!!!