• C++:浅拷贝和深拷贝简析


    目录

    浅拷贝: 

             深拷贝:

    总代码:


    我们先来看一段代码

    1. #include <iostream>
    2. using namespace std;
    3. class student {
    4. public:
    5. student() //默认的构造函数
    6. {
    7. cout << "调用了默认构造函数" << endl;
    8. }
    9. student(int age, int height)//半缺省的构造函数
    10. {
    11. _age = age;
    12. _height = new int(height); //在堆区开辟内存
    13. cout << "调用了半缺省构造函数" << endl;
    14. }
    15. ~student()
    16. {
    17. if (_height)
    18. {
    19. delete _height;
    20. _height = NULL;
    21. }
    22. cout << "调用了析构函数" << endl;
    23. }
    24. int _age; //年龄
    25. int* _height; //体重
    26. };
    27. void test01(void) {
    28. student p1(10, 90);
    29. cout << "p1的年龄是" << p1._age << "体重是" << *p1._height << endl;
    30. student p2(p1);//浅拷贝
    31. cout << "p2的年龄是" << p2._age << "体重是" << *p2._height << endl;
    32. }
    33. int main(void)
    34. {
    35. test01();
    36. return 0;
    37. }

    在这里我定义了两个 p1和p2,然后将p1通过浅拷贝复制给了p2

     然后得到如下结果

     

    我们可以看到虽然已经成功赋值,但是编译器报错,这就和浅拷贝有关

    浅拷贝: 

    以上面为例

     简单来说p2通过浅拷贝,和p1指向了同一个空间

    由于栈区的规则是先进后出,当执行完拷贝构造函数的时候,我们程序就会先执行p2的析构函数,导致释放堆区开辟的数据,然后这个已经释放的内存又要再被p1释放,这样就会报错

    就是说同一块内存数据被释放了两次,这是编译器所不允许的

     同时,因为是指向同一个空间,如果p1发生改变,那么p2也会受到影响

    比如我们修改一下p1的数据

    1. void test01(void) {
    2. student p1(1000000, 90000000);//修改了一下p1的数据
    3. cout << "p1的年龄是" << p1._age << "体重是" << *p1._height << endl;
    4. student p2(p1);
    5. cout << "p2的年龄是" << p2._age << "体重是" << *p2._height << endl;
    6. }

    然后就是这个结果

     浅拷贝总结:1.会析构两次2.一个对象改变会影响另一个对象

    所以说为了避免这种问题,我们就引入了深拷贝

    深拷贝:

     什么是深拷贝呢?

    深拷贝就是我p2,也向内存申请一个和p1一样大的,用来存储数据的空间,同时将数据复制,然后p2指向这个新空间

     这样析构的时候,p1和p2都只析构自己对应的空间,这样就不会报错了

    为了实现这种深拷贝,我们就需要加入这段代码

    1. student(const student& p) //这里隐藏了this指针,实际上是p2(p1)
    2. {
    3. _age = p._age;
    4. _height = new int(*p._height);//复制+开一样大的新空间
    5. }

    结果如下

     这样编译器就不会报错了,而且看出析构了两次

    总代码:

    1. #include <iostream>
    2. using namespace std;
    3. class student {
    4. public:
    5. student() //默认的构造函数
    6. {
    7. cout << "调用了默认构造函数" << endl;
    8. }
    9. student(const student& p) {
    10. _age = p._age;
    11. _height = new int(*p._height);
    12. }
    13. student(int age, int height)//半缺省的构造函数
    14. {
    15. _age = age;
    16. _height = new int(height); //在堆区开辟内存
    17. cout << "调用了半缺省构造函数" << endl;
    18. }
    19. ~student()
    20. {
    21. if (_height)
    22. {
    23. delete _height;
    24. _height = NULL;
    25. }
    26. cout << "调用了析构函数" << endl;
    27. }
    28. int _age; //年龄
    29. int* _height; //体重
    30. };
    31. void test01(void) {
    32. student p1(1000000, 90000000);
    33. cout << "p1的年龄是" << p1._age << "体重是" << *p1._height << endl;
    34. student p2(p1);
    35. cout << "p2的年龄是" << p2._age << "体重是" << *p2._height << endl;
    36. }
    37. int main(void)
    38. {
    39. test01();
    40. return 0;
    41. }

  • 相关阅读:
    TDengine 上榜 BenchCouncil 全球首个开源贡献榜
    SpringCloud无介绍快使用,sentinel注解@SentinelResource的基本使用(二十三)
    lambda的使用案例(1)
    多层神经网络和激活函数
    支付媒介的演变与创新
    数据分析 第二周 (条形图,散点图,直方图,numpy运算和数组广播机制)笔记
    DDD基础_领域设计10大基础概念
    平衡三进制分布式计算
    Vue中实现在线画流程图实现
    第二十一条:为传诸后世而设计接口
  • 原文地址:https://blog.csdn.net/qq_62718027/article/details/125633510