zoukankan      html  css  js  c++  java
  • Cpp下的深拷贝与浅拷贝探究

    下面,通过代码来说说C++中的深浅拷贝

    #define   _CRT_SECURE_NO_WARNINGS
    #include<iostream>
    using namespace std;
    class Name
    {
    public:
        Name(const char*myp){
            m_len = strlen(myp);
            mp = (char*)malloc(m_len + 1);
            strcpy(mp, myp);
        }
        ~Name(){
            if (mp != NULL)
            {
                free(mp);
                mp = NULL;
                m_len = 0;
            }
        }
    private:
        char *mp;
        int m_len;
    };
    
    void playmain(){
        Name obj1("abcdef");
        Name obj2 = obj1;  // 执行默认拷贝构造函数
    }
    int main()
    {
        playmain();
        cout <<"hello world"<<endl;
        system("pause");
        return 0;
    }

    我们通过断点,一步一步地调试程序:

    继续往下走:

    继续往下走:

    由于我们并没有重写自己的拷贝构造函数,因此执行的是默认的拷贝构造函数。当Name obj2=obj1执行完毕后,也就是函数playmain()执行完毕了,开始调用对象的析构函数:

    首先析构的是obj2,当其析构完毕后,程序返回:

    我们接着往下走:

    继续F11往下走,我们会发现程序崩溃了:

    下面,我们来分析一下,为什么程序会崩溃在这里?原因很简单,因为我们重写自己的拷贝构造函数,而使用了默认的拷贝构造函数,也就是C++编译器为我们进行了一次浅拷贝。那么何为浅拷贝呢?下面来看张图:

    也就是说,当我们第一次析构对象obj2的时候,已经将内存空间0x1111释放了,而obj1和obj2都指向了同一块内存空间,当obj1执行析构函数的时候,它所指向的内存空间已经被释放,再次进程释放,肯定程序会崩溃。到此 ,我们清楚知道,导致程序崩溃的原因是C++编译器仅仅执行了浅拷贝,而浅拷贝的根源在于我们没有重写自己的拷贝构造函数,所以解决办法,当然是重写自己的拷贝构造函数,从而实现深拷贝-------将对象完完全全的赋值一份(包括指针指向的内存空间也复制一份)

    再次执行程序,不会出现崩溃现象。上述对应的内存四区模型如下:

     同理,如下代码中也会出现程序崩溃,也需要我们显式重载"="运算符

    没有重载=运算符内存四区模型如下:

    初始条件:


    执行等号操作后:

    解决方案:

    #define  _CRT_SECURE_NO_WARNINGS 
    #include <iostream>
    using namespace std;
    
    class  Name
    {
    public:
        Name(const char *myp)
        {
            m_len = strlen(myp);
            m_p =(char *) malloc(m_len + 1); 
            strcpy(m_p, myp);
        }
    
        //解决方案: 手工的编写拷贝构造函数 使用深copy
        Name(const Name& obj1)
        {
            m_len = obj1.m_len;
            m_p = (char *)malloc(m_len + 1);
            strcpy(m_p, obj1.m_p);
        }
        //obj3 = obj1;  // C++编译器提供的 等号操作 也属 浅拷贝
        //obj3.operator=(obj1)
        Name& operator=(Name &obj1) // 重载等号运算符
        {
            //先释放旧的内存
            if (this->m_p != NULL)
            {
                delete[] m_p;
                m_len = 0;
            }
            //2 根据obj1分配内存大小
            this->m_len = obj1.m_len;
            this->m_p = new char [m_len+1];
            
            //把obj1赋值
            strcpy(m_p, obj1.m_p);
            return *this;
        }
        ~Name()
        {
            if (m_p != NULL)
            {
                free(m_p);
                m_p = NULL;
                m_len = 0;
            }
        }
    protected:
    private:
        char *m_p ;
        int m_len; 
    };
    
    //对象析构的时候 出现coredump
    void objplaymain()
    {
        Name obj1("abcdefg");
        Name obj2 = obj1;  //C++编译器提供的 默认的copy构造函数  浅拷贝
        Name obj3("obj3");
    
        obj3 = obj1;  // C++编译器提供的 等号操作 也属 浅拷贝
        //obj3.operator=(obj1)
        //operato=(Name &obj1)
        obj1 = obj2 = obj3;
        //obj2.operator=(obj3);
        //obj1 = void;
    }
    
    void main()
    {
        objplaymain();
        cout<<"hello..."<<endl;
        system("pause");
        return ;
    }
  • 相关阅读:
    《网络攻防实践》6.0
    《网络攻防实践》5.0
    Docker 本地镜像发布到阿里云(完结篇)
    Vue 实战-9 Vue公共js功能函数的封装和使用
    Vue 实战-8 单独运行测试.js文件
    Docker 常用安装
    DockerFile 解析及案例
    Docker 容器数据卷
    Docker 镜像原理
    多字段模糊匹配 -->搜索功能(mysql原生语句实现)
  • 原文地址:https://www.cnblogs.com/vipchenwei/p/7294416.html
Copyright © 2011-2022 走看看