浅拷贝:简单的赋值拷贝操作。
深拷贝:在堆区重新申请空间,进行拷贝操作。
C++中在对一个已知对象进行拷贝的时候,会调用类中的拷贝构造函数,如果程序员未定义拷贝构造函数,则会调用编译器默认的拷贝构造函数进行值拷贝!
看一个简单的例子:
#include <iostream>
using namespace std;
class Person {
public:
Person() { /*默认构造函数*/
cout << "Person默认构造桉树的调用" << endl;
}
Person(int age,int height) { /*有参构造函数*/
m_age = age;
m_height = new int(height); //在堆区开辟内存
cout << "Person有参构造函数的调用" << endl;
}
~Person() {
if (m_height != NULL) {
delete m_height;
m_height = NULL;
}
cout << "Person析构函数的调用" << endl;
}
int m_age; //年龄
int* m_height; //体重
};
void test01(void) {
Person p1(18,160);
cout << "p1的年龄是" << p1.m_age << "体重是" << *p1.m_height << endl;
Person p2(p1);
cout << "p2的年龄是" << p2.m_age << "体重是" << *p2.m_height << endl;
}
int main(void)
{
test01();
system("pause");
return 0;
}
可以看出在test01()函数中先调用有参构造函数定义了对象p1,再调用拷贝构造函数将p1的数据复制给p2。代码看似没有错误,运行可以看到结果如下:
可以发现程序运行出现了一个异常,这是什么原因呢?
这是由于编译系统在我们没有自己定义拷贝构造函数时,会在拷贝对象时调用默认拷贝构造函数,进行的是浅拷贝!即对指针拷贝后会出现两个指针指向同一个内存空间。
由于栈区的规则是先进后出,当执行完拷贝构造函数的时候,就会执行p2的析构函数,导致释放堆区开辟的数据。因此当执行p1的析构函数时就会导致内存释放2次,程序崩溃。
所以,在对含有指针成员的对象进行拷贝时,必须自己定义拷贝构造函数,达到深拷贝的目的,才能必变内存重复释放。
增加拷贝构造函数后的代码:
#include <iostream>
using namespace std;
class Person {
public:
Person() { /*默认构造函数*/
cout << "Person默认构造桉树的调用" << endl;
}
Person(int age,int height) { /*有参构造函数*/
m_age = age;
m_height = new int(height); //在堆区开辟内存
cout << "Person有参构造函数的调用" << endl;
}
//拷贝构造函数
Person(const Person& p) {
cout << "Person拷贝构造函数!" << endl;
//如果不利用深拷贝在堆区创建新内存,会导致浅拷贝带来的重复释放堆区问题
m_age = p.m_age;
m_height = new int(*p.m_height);
}
~Person() {
if (m_height != NULL) {
delete m_height;
m_height = NULL;
}
cout << "Person析构函数的调用" << endl;
}
int m_age; //年龄
int* m_height; //体重
};
void test01(void) {
Person p1(18,160);
cout << "p1的年龄是" << p1.m_age << "体重是" << *p1.m_height << endl;
Person p2(p1);
cout << "p2的年龄是" << p2.m_age << "体重是" << *p2.m_height << endl;
}
int main(void)
{
test01();
system("pause");
return 0;
}
即在堆区重新开辟一片内存保存数据,这样就可以避免内存重复释放!!!