一:浅拷贝
同一个类型的对象之间可以赋值,使得两个对象的成员变量的值相同,两个对象仍然是独立的对象,这种情况被称为浅拷贝。
一般情况下,浅拷贝没有任何副作用,但是当类中有指针,并且指针指向动态分配的内存空间,析构函数做了动态内存释放的处理,会导致内存问题。
下面是浅拷贝的例子:
//构造函数来初始化属性
class Student
{
public:
Student()
{
m_Name=NULL;
age=0;
}
Student(char *name,int age)
{
m_Name=(char *)malloc(strlen(name)+1); //堆区的空间
strcpy(m_Name,age);
this->age=age;
}
~Student()
{
cout<<"析构函数调用\n";
if(m_Name!=NULL)
{
free(m_Name);
m_Name=NULL; //防止出现野指针
}
}
char *m_Name;
int age;
};
void test01()
{
Student stu1("tong",10); //调用有参构造函数
Student stu2(stu1); //调用拷贝构造
}
int main()
{
test01();
return 0;
}
注意:上面的程序运行的话会崩掉。
解析:由于上面的类没有提供拷贝构造函数, 系统会提供默认的拷贝构造函数,这种情况下是简单的拷贝;由于是简单的拷贝,会使stu2对象中m_Name和stu1对象中m_Name指向相同的内存空间,当stu1执行到析构函数时,指向的内存(0x0001)就会被释放(free),这时候stu2指向的这块空间就不存在了,那会stu2的析构执行时就会出错(程序也会崩掉)。下面是stu1和stu2的图解:
二:深拷贝
由于系统默认提供的拷贝构造函数只是简单的赋值,如果属性里有指向堆区的数据,那么浅拷贝会导致重复释放内存的异常问题。
那么这时候就要用到深拷贝,也就是自己为类提供个拷贝构造函数,为属性的成员(指针)另外开辟个独立堆区空间,这样的就叫做深拷贝。
代码的更改如下:
class Student
{
public:
Student()
{
m_Name=NULL;
age=0;
}
Student(char *name,int age)
{
m_Name=(char *)malloc(strlen(name)+1); //堆区的空间
strcpy(m_Name,age);
this->age=age;
}
Student(const Student &p)
{
age=p.age;
m_Name=(char *)malloc(strlen(p.m_Name)+1);
strcpy(m_Name,p.m_Name);
}
~Student()
{
cout<<"析构函数调用\n";
if(m_Name!=NULL)
{
free(m_Name);
m_Name=NULL; //防止出现野指针
}
}
char *m_Name;
int age;
};
void test01()
{
Student stu1("tong",10); //调用有参构造函数
Student stu2(stu1); //调用拷贝构造
}
int main()
{
test01();
return 0;
}
注:这样的话,代码的运行就不会出现崩溃的问题了。
原文:https://www.cnblogs.com/Unclebigdata/p/14387380.html