C++中的深拷贝与浅拷贝
浅拷贝问题抛出:
#define _CRT_SECURE_NO_WARNINGS
#include "iostream"
using namespace std;
/*
浅拷贝问题抛出
*/
class ShallowCopy
{
public:
ShallowCopy(const char * myp)
{
len = strlen(myp);
p = (char *)malloc(len + 1); //指针指向谁,就把谁的地址给指针。把内存空间首地址给p,+1是\0,没有的话会内存越界。
strcpy(p, myp);//把myp指针所指向的内存空间的数据copy到p所指向的内存空间。
}
~ShallowCopy()
{
if ( p != NULL )
{
free(p);
p = NULL;
len = 0;
}
}
private:
char * p;
int len;
};
void ObjPlaymain()
{
ShallowCopy obj1("abcdefg");
/*
调用obj2类的copy构造函数,没写,调用c++编译器提供的copy构造函数(浅拷贝)
c++编译器偷懒,浅拷贝,把obj1的属性拷贝到obj2,只把指针变量的值拷贝过来了,没有另外开辟内存。
*/
ShallowCopy obj2 = obj1;
}
void main()
{
ObjPlaymain();
system("pause");
}
这样程序会出现coredump, 可以用如下内存图理解:
c++编译器默认的copy构造函数,浅拷贝,把obj1的属性拷贝到obj2,只把指针变量的值拷贝过来了,没有另外开辟内存。这样obj1和obj2的p指针指向同一块内存空间。
析构的时候,先析构obj2,把那块内存空间析构掉了,同时把内存空间置成NULL,把len置成0。然后析构obj1,此时那块内存空间是垃圾值(已经析构过了),则此时的obj1的指针p是个野指针,调用obj1的析构函数,同一块内存空间被析构了2次。析构的时候程序会出现coredump。
那怎么办呢?
蓝色箭头是我们的解决方案。既然c++编译器提供的copy构造函数不行,我们就手动编写copy构造函数呗,让2个指针不要指向同一块内存,给它重新开辟。所以必要的时候,必须手工编写copy构造函数。
下面是解决方案:
#define _CRT_SECURE_NO_WARNINGS
#include "iostream"
using namespace std;
/*
浅拷贝问题解决:不使用c++编译器提供的copy构造函数,手工编写copy构造函数,使用深拷贝。
*/
class DeepCopy
{
public:
DeepCopy(const char * myp)
{
len = strlen(myp);
p = (char *)malloc(len + 1 );
strcpy(p, myp);
}
DeepCopy(const DeepCopy & obj1)
{
len = strlen(obj1.p);
p = (char *)malloc(len + 1);
strcpy(p, obj1.p);
}
~DeepCopy()
{
if (p != NULL)
{
free(p);
p = NULL;
len = 0;
}
}
private:
char * p;
int len;
};
void ObjPlaymain()
{
DeepCopy obj1("abcdefg");
DeepCopy obj2 = obj1;
}
void main()
{
ObjPlaymain();
system("pause");
}
这样就不会出现问题了,ok!
之前说过初始化和赋值不一样,如果用=连接obj1和obj2,又会怎样呢?
#define _CRT_SECURE_NO_WARNINGS
#include "iostream"
using namespace std;
/*
=也不行,需要重载操作符
*/
class DeepCopy
{
public:
DeepCopy(const char * myp)
{
len = strlen(myp);
p = (char *)malloc(len + 1);
strcpy(p, myp);
}
~DeepCopy()
{
if (p != NULL)
{
free(p);
p = NULL;
len = 0;
}
}
private:
char * p;
int len;
};
void ObjPlaymain()
{
DeepCopy obj1("abcdefg");
DeepCopy obj2("obj2");
/*
=操作,把obj1的属性copy给obj2,用c++默认的copy构造函数,
和刚才浅拷贝一样,析构时出现问题,需要重载操作符=
*/
obj2 = obj1;
}
void main()
{
ObjPlaymain();
system("pause");
}
结果发现,和刚才一样,也会出现同样的问题。
依旧用内存图解释:
人家obj1和obj2本来指向不同的内存空间,各不干扰。结果你"obj2=obj1"一下,把obj1的值赋值给obj2,obj2的p和len和obj1一模一样,把人家obj2的p指针活生生指到obj1那块内存空间了,结果造成obj1和obj2的指针又指向同一块内存空间了,析构的时候又出现coredump。而且,原来人家obj2的0xbb11那块内存被暴露出来了,内存泄露了。
这个"="也太肤浅了吧,看来需要操作符重载喽!