浅拷贝和深拷贝是两种常用的对象复制方式,区别在于拷贝对象是所进行的内存操作不同
在没用定义拷贝构造函数的情况下,系统会调用默认的拷贝构造函数--就是浅拷贝,这个是可以不用自己定义的,它可以完成简单的值的拷贝--复制.数据成员中没有指针时,浅拷贝方式是可行的;并且被拷贝的对象中成员变量的值发生变化不会影响原来对象中的成员变量的值,如:
#include<iostream>
using namespace std;
class Test
{
public:
Test(int a) :m_a(a) {};
//这是编译器为我们提供的默认的拷贝构造函数形式,不写也可以
Test(const Test& test)
{
this->m_a = test.m_a;
}
int m_a;
};
int main()
{
Test obj1(5);
Test obj2(obj1);
cout << "obj1=" << obj1.m_a << endl;//obj1.m_a=5;
cout << "obj2=" << obj2.m_a << endl;//obj2.m_a=5;
cout << "&obj1=" << &obj1 << endl;//&obj1=0000008862F3F9E4
cout << "&obj2=" << &obj2 << endl;//&obj1=0000008862F3F9E4
obj1.m_a = 10;
cout << "obj1=" << obj1.m_a << endl;//obj1.m_a=10;
cout << "obj2=" << obj2.m_a << endl;//obj2.m_a=5;
obj2.m_a = 10;
cout << "obj1=" << obj1.m_a << endl;//obj1.m_a=10;
cout << "obj2=" << obj2.m_a << endl; //obj2.m_a=10;
return 0;
}
上面的代码就成功说明了如果数据是基本类型(int,double..),那么对浅拷贝后的其中一个变量进行修改不会影响原来数据的值,两个变量所占用的内存在物理上已近分开.
但是,如果在浅拷贝中,数据成员拥有指针时,拷贝后两个指针会指向同一块内存(同一块地址/同一个堆区),当对象快结束时,会调用两次析构函数,对这个内存释放两次,就会导致指针悬挂,如:
class Person {
public:
int age;
int* ptr;
Person(int a, int p) : age(a), ptr(new int(p)) {}
~Person() {
delete ptr;
}
};
int main() {
Person p1(18, 100);
Person p2 = p1; // 拷贝构造函数
std::cout << *(p1.ptr) << " " << *(p2.ptr) << endl; // 输出:100 100
*(p1.ptr) = 200;
cout << *(p1.ptr) << " " << *(p2.ptr) << endl; // 输出:200 200
delete p1.ptr;
cout << *(p2.ptr) << endl; // 此处已经释放内存,输出未定义
return 0;
}
因此,必须使用深拷贝,深拷贝与浅拷贝的区别就在于深拷贝会在堆内存中另外申请空间来储存数据(新的堆区空间进行拷贝),从而也就解决了指针悬挂的问题。简而言之,当数据成员中有指针时,必须要用深拷贝。如:
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)
{
this->m_Age = p.m_Age;
//this->m_Height = p.m_Height;
this->m_Height = new int(*p.m_Height);//在堆区上重新开辟一块内存空间
cout << "Person的拷贝构造函数" << endl;
}
~Person()
{
if (m_Height != NULL)
{
delete m_Height;
}
cout << "Person的析构函数调用" << endl;
}
int m_Age;
int* m_Height;
};
void test()
{
Person p1(21, 163);
cout << "p1的年龄:" << p1.m_Age << "p1身高:" << *p1.m_Height << endl;
Person p2(p1);
cout << "p2的年龄:" << p2.m_Age << "p2身高:" << *p2.m_Height << endl;
}
int main()
{
test();
return 0;
}
结果:成功运行
Person的有参构造函数
p1的年龄:21p1身高:163
Person的拷贝构造函数
p2的年龄:21p2身高:163
Person的析构函数调用
Person的析构函数调用