Cpp下的深拷贝与浅拷贝探究

下面,通过代码来说说C++中的深浅拷贝

#define   _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
class Name
{
public:
Name(const char*myp){
m_len = strlen(myp);
mp = (char*)malloc(m_len + );
strcpy(mp, myp);
}
~Name(){
if (mp != NULL)
{
free(mp);
mp = NULL;
m_len = ;
}
}
private:
char *mp;
int m_len;
}; void playmain(){
Name obj1("abcdef");
Name obj2 = obj1; // 执行默认拷贝构造函数
}
int main()
{
playmain();
cout <<"hello world"<<endl;
system("pause");
return ;
}

我们通过断点,一步一步地调试程序:

Cpp下的深拷贝与浅拷贝探究

继续往下走:

Cpp下的深拷贝与浅拷贝探究

继续往下走:

Cpp下的深拷贝与浅拷贝探究

由于我们并没有重写自己的拷贝构造函数,因此执行的是默认的拷贝构造函数。当Name obj2=obj1执行完毕后,也就是函数playmain()执行完毕了,开始调用对象的析构函数:

Cpp下的深拷贝与浅拷贝探究

首先析构的是obj2,当其析构完毕后,程序返回:

Cpp下的深拷贝与浅拷贝探究

我们接着往下走:

Cpp下的深拷贝与浅拷贝探究

继续F11往下走,我们会发现程序崩溃了:

Cpp下的深拷贝与浅拷贝探究

下面,我们来分析一下,为什么程序会崩溃在这里?原因很简单,因为我们重写自己的拷贝构造函数,而使用了默认的拷贝构造函数,也就是C++编译器为我们进行了一次浅拷贝。那么何为浅拷贝呢?下面来看张图:

Cpp下的深拷贝与浅拷贝探究

也就是说,当我们第一次析构对象obj2的时候,已经将内存空间0x1111释放了,而obj1和obj2都指向了同一块内存空间,当obj1执行析构函数的时候,它所指向的内存空间已经被释放,再次进程释放,肯定程序会崩溃。到此 ,我们清楚知道,导致程序崩溃的原因是C++编译器仅仅执行了浅拷贝,而浅拷贝的根源在于我们没有重写自己的拷贝构造函数,所以解决办法,当然是重写自己的拷贝构造函数,从而实现深拷贝-------将对象完完全全的赋值一份(包括指针指向的内存空间也复制一份)

Cpp下的深拷贝与浅拷贝探究

再次执行程序,不会出现崩溃现象。上述对应的内存四区模型如下:

Cpp下的深拷贝与浅拷贝探究

同理,如下代码中也会出现程序崩溃,也需要我们显式重载"="运算符

Cpp下的深拷贝与浅拷贝探究

没有重载=运算符内存四区模型如下:

初始条件:

Cpp下的深拷贝与浅拷贝探究

执行等号操作后:

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 + );
strcpy(m_p, myp);
} //解决方案: 手工的编写拷贝构造函数 使用深copy
Name(const Name& obj1)
{
m_len = obj1.m_len;
m_p = (char *)malloc(m_len + );
strcpy(m_p, obj1.m_p);
}
//obj3 = obj1; // C++编译器提供的 等号操作 也属 浅拷贝
//obj3.operator=(obj1)
Name& operator=(Name &obj1) // 重载等号运算符
{
//先释放旧的内存
if (this->m_p != NULL)
{
delete[] m_p;
m_len = ;
}
//2 根据obj1分配内存大小
this->m_len = obj1.m_len;
this->m_p = new char [m_len+]; //把obj1赋值
strcpy(m_p, obj1.m_p);
return *this;
}
~Name()
{
if (m_p != NULL)
{
free(m_p);
m_p = NULL;
m_len = ;
}
}
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++编译器提供的 等号操作 也属 浅拷贝
//obj3.operator=(obj1)
//operato=(Name &obj1)
obj1 = obj2 = obj3;
//obj2.operator=(obj3);
//obj1 = void;
} void main()
{
objplaymain();
cout<<"hello..."<<endl;
system("pause");
return ;
}
上一篇:indexOf()的用法


下一篇:java.lang.StringBuffer源码分析