浅拷贝主要出现的问题是不是值拷贝:先看代码
#include <iostream>
using namespace std;
class Test
{
public:
Test(){};
Test(char *p)
{
this->ptr = p;
}
~Test()
{
if (this->ptr != NULL)
{
delete this->ptr;
this->ptr = NULL;
}
}
private:
char *ptr;
};
int main()
{
Test t1("hello,world");
Test t2 = t1;
return 0;
}
这段代码即为浅拷贝 :这段代码存在的问题
先理以下程序的执行顺序,在初始化t1对象的时候,"hello,world"存在的是静态数据区,然后ptr指向了这块区域,然后初始化t2的时候,调用了默认的拷贝构造,此时t2的ptr也指向了这块区域 ,然后程序时,t1,t2 对象要析构,调用析构函数
问题:首先我们要知道 不能对指向静态存储区(全局变量)或内存区局部变量)的指针应用free(但可以对空指针NULL应用
free),所以,在第一次析构时程序已经down掉,根本就执行不到二次析构
既然我们不能对静态存储区进行释放,那么我们对代码进行如下改进
Test(char *p)
{
this->ptr = new char[strlen(p) + 1];
strcpy(this->ptr, p);
}
将构造函数改成这个样子 ,那么这样可以了嘛? 答案是否定的
t1确实将字符串拷贝到堆内存中,可是t2的ptr指针也指向了和t1的ptr指向的相同的堆内存,所以这段程序挂掉是在第二次析构的时候,因为我们不能对堆上同一块内存进行两次析构
我们对代码在进行改进
#include <iostream>
using namespace std;
class Test
{
public:
Test(){};
Test(const Test &another)
{
this->ptr = new char[strlen(another.ptr) + 1];
strcpy(this->ptr, another.ptr);
}
Test(char *p)
{
this->ptr = new char[strlen(p) + 1];
strcpy(this->ptr, p);
}
void print()
{
cout << this->ptr << endl;
}
~Test()
{
if (this->ptr != NULL)
{
delete this->ptr;
this->ptr = NULL;
}
}
private:
char *ptr;
};
int main()
{
Test t1("hello,world");
Test t2 = t1;
t1.print();
t2.print();
return 0;
}
这样就可以了,我们对t2进行了值拷贝,也就是深拷贝,也就不会发生错误
同样的如果我们加上代码
Test t3;
t3=t1;
这样我们可以自己重写=重载就可以了
Test &operator=(const Test & another)
{
this->ptr = new char[strlen(another.ptr) + 1];
strcpy(this->ptr, another.ptr);
return *this;
}
但是还有一个问题,如果t3的ptr指针已经指向了堆上的一块内存,那么我们重新拷贝的时候,因该要将原有的堆内存的进行释放,如果不将原有的堆内存进行释放,将会存堆内存泄漏
所以我们应该重写=重载
Test &operator=(const Test & another)
{
if (this->ptr != NULL)
{
delete this->ptr;
}
this->ptr = new char[strlen(another.ptr) + 1];
strcpy(this->ptr, another.ptr);
return *this;
}
这样就能解决上面的问题了