深拷贝与浅拷贝
深拷贝与浅拷贝
浅拷贝:简单的赋值拷贝操作,或者说编译器自己生成的默认拷贝函数
深拷贝:在堆区重新申请空间,进行拷贝操作
class Person { public: //无参(默认)构造函数 Person() { cout << "无参构造函数!" << endl; } //有参构造函数 Person(int age, int height) { cout << "有参构造函数!" << endl; m_age = age; //因为new是在堆区存储数据,所以用一个指针接收返回数据 m_height = new int(height); } //析构函数 专门释放堆区数据的 ~Person() { cout << "析构函数!" << endl; if (m_height != NULL) { //释放在堆区中的数据。 delete m_height; //防止野指针出现,设置成空指针。 m_height = NULL; } } public: int m_age; int* m_height; }; void test01() { Person p1(18, 180); cout << "p1的年龄: " << p1.m_age << " 身高: " << *p1.m_height << endl; Person p2(p1); cout << "p2的年龄: " << p2.m_age << " 身高: " << *p2.m_height << endl; } int main() { test01(); system("pause"); return 0; }
当前代码运行起来之后会报错:
因为在有参构造函数中创建了一个堆区的数据,在执行Person p2(p1)的时候编译器默认的拷贝函数也会简单的在栈上存储height的地址,当离开test01这个函数体的时候自动调用析构函数,栈上的数据是先进后出(因为test01函数中没有new,数据在栈上),所以先释放p2的数据,这里的析构函数是自己写的,可以看到释放了m_height在堆上的数据,当在释放p1(注意p1上的m_height存储的是堆地址,此时它是有值的,不会因为p2释放了导致它在栈上的值没有了)的时候又会重新释放,根据栈上的地址找堆,发现找不到了,导致重复释放报错。
上述就是因为编译器默认的浅拷贝造成的,如果属性有在堆区开辟的,一定要自己提供拷贝构造函数,防止浅拷贝带来的问题
自己创建拷贝函数解决:
class Person { public: //无参(默认)构造函数 Person() { cout << "无参构造函数!" << endl; } //有参构造函数 Person(int age, int height) { cout << "有参构造函数!" << endl; m_age = age; //因为new是在堆区存储数据,所以用一个指针接收返回数据 m_height = new int(height); } //拷贝构造函数 Person(const Person& p) { cout << "拷贝构造函数!" << endl; //如果不利用深拷贝在堆区创建新内存,会导致浅拷贝带来的重复释放堆区问题 m_age = p.m_age; //这样不论调用多少次拷贝函数,前后的m_height中存储的堆地址都不是一样的了 m_height = new int(*p.m_height); } //析构函数 专门释放堆区数据的 ~Person() { cout << "析构函数!" << endl; if (m_height != NULL) { //释放在堆区中的数据。 delete m_height; //防止野指针出现,设置成空指针。 m_height = NULL; } } public: int m_age; int* m_height; }; void test01() { Person p1(18, 180); cout << "p1的年龄: " << p1.m_age << " 身高: " << *p1.m_height << endl; Person p2(p1); cout << "p2的年龄: " << p2.m_age << " 身高: " << *p2.m_height << endl; } int main() { test01(); system("pause"); return 0; }
结果:
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决
· 提示词工程——AI应用必不可少的技术