C++ 学习日志——深拷贝和浅拷贝

用代码分析深拷贝和浅拷贝的区别,利用深拷贝解决浅拷贝的问题。

目录

代码

浅拷贝的问题

深拷贝解决


代码

#include <iostream>
#include <string>
using namespace std;

class Person{
public:
    int s_age;
    int *m_hight;
    
    Person(){
        cout<<"无参构造函数"<<endl;
    }  
    Person(int age,int height){
        cout<<"有参构造函数"<<endl;
        s_age = age;
        //从堆区申请一块内存 m_hight 指针指向该内存
        m_hight = new int(height);
    }
    
    Person(const Person &p){
        cout<<"拷贝构造函数"<<endl;
        s_age = p.s_age;
        //编译器默认实现这个代码 拷贝的只是一个值,但指针指向的还是原来的堆区,并没有重写创建
       //m_hight = p.m_hight 
       //所以需要再利用new 重新创建内存
        m_hight = new int(*p.m_hight);
    }
    
    ~Person(){
        //根据栈区先进后出原则,p2先释放 进入析构函数
        if(m_hight!=NULL){
            delete m_hight; //释放堆区的内存
            m_hight = NULL;
        }
        cout<<"析构函数"<<endl;
    }
    
    
};
void test1(){
    
    Person p1(20,180);
    cout<<"p1_age:"<<p1.s_age<<"  p1_hight:"<<*p1.m_hight<<endl;
    
    Person p2(p1);
    cout<<"p2_age:"<<p2.s_age<<"  p2_hight:"<<*p2.m_hight<<endl;
    
}

int main()
{
    test1();
    return 0;
}

浅拷贝的问题

        我们创建第一个对象p1的时候,利用构造函数向内存申请一个堆区的内存,这里叫他 memory1,然后再利用拷贝构造函数,创建一个p2,如果利用浅拷贝(即编辑器自己创建),m_hight = p.m_hight实现,只会让p2 的 m_hight 指针指向 p1的 memory1,如下图。最终会导致析构函数执行的时候,根据先入后出的原则,p2会先释放memory1的内存,p1再去释放的时候,该内存已经被释放掉了,属于非法操作,堆区内存重复释放,这是浅拷贝带来的问题。


深拷贝解决

        若要避免浅拷贝带来的问题,需要重写拷贝函数,我们在拷贝构造函数中重新去申请一块内存,和构造函数一样。

Person(const Person &p){
    cout<<"拷贝构造函数"<<endl;
    s_age = p.s_age;
    //m_hight = p.m_hight  编译器默认实现这个代码
    m_hight = new int(*p.m_hight);
}

        之后呢,p2的 m_hight 不再指向p1的内存(memory1),p2有自己的内存,这样释放的时候,各自释放各自的堆区内存空间,不再有冲突。这里的p2创建一个新的堆区内存空间 memory2。p1和p2的m_hight指向不同的内存空间,这样执行析构不会出现内存重复释放的问题。

猜你喜欢

转载自blog.csdn.net/qq_53734051/article/details/126418637