解析浅拷贝的缺陷及其解决方案

浅拷贝的缺陷

类的定义:

class  Name
{
public:
    Name(const char *myp)
    {
        m_len = strlen(myp);
        m_p =(char *) malloc(m_len + 1); //
        strcpy(m_p, myp);
    }
~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构造函数  浅拷贝  //解释图为:图1
    //Name obj3("obj3");

    //obj3 = obj1;  // C++编译器提供的 等号操作 也属 浅拷贝   //解释图为:图2
}

void main()
{
    objplaymain();
    cout<<"hello..."<<endl;
    system("pause");
}

在这个程序中,首先abcdefg存储在内存全局区中,obj1初始化调用有参构造函数Name(const char *myp),然后使用malloc()函数动态分配内存(分配在堆区),并把这个内存空间的地址赋给P,strcpy(m_p, myp)则将myp的数据“abcdefg”赋值到堆区中,这时P指向的内存空间的数据就是“abcdefg”,完成了初始化工作。

Name obj2 = obj1;  调用C++编译器提供的 默认的copy构造函数 ,是浅拷贝,则只是将obj1的属性拷贝给了obj2,而并未重新开辟新的内存空间,这时,obj1  obj2属性是一样的,P指向的内存空间也是同一个。

类的析构函数首先会析构掉obj2,这时obj2的P指针指向的内存空间就释放了。然后接着析构obj1的内存空间。这就有问题了,因为obj1和obj2  P指针指向的内存空间是一样,P指向的内存空间已经释放了,obj2析构时,想要再次释放内存空间,就出现同一内存出现多次释放的错误。

因此,浅拷贝存在缺陷,在写程序时,应尽量避免浅拷贝的使用。C++编译器默认提供的拷贝构造函数机制就是浅拷贝,在写类时,特别注意浅拷贝的缺陷。

文字没看懂,请看原理图:

以上是解释了机制,在C++中,C++的默认拷贝构造函数和赋值操作,使用的都是浅拷贝,默认拷贝构造函数为图1,赋值操作的浅拷贝为下图(图2);机制原理相似。不再赘述。本来obj3指向0xbb11,经过赋值操作,obj3指向了0xaa11,这样就造成了0xbb11内存泄漏,并且0xaa11重复释放的错误。

解决方案(C++类)

对于拷贝构造函数造成的浅拷贝,解决方案就是在类中重写拷贝构造函数。例如:

    //Name obj2 = obj1;
    //解决方案: 手工的编写拷贝构造函数 使用深copy
    Name(const Name& obj1)
    {
        m_len = obj1.m_len;
        m_p = (char *)malloc(m_len + 1);
        strcpy(m_p, obj1.m_p);
    }

对于赋值操作造成的浅拷贝,解决方案同样是在类中重写赋值函数。

文中两图来源于传智播客。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值