深拷贝与浅拷贝

深拷贝与浅拷贝

之前在学c++的时候,接触到了这两个概念,不过当时也不能完全理解,然后这两天看《深度探索C++对象模型》中Copy Constructor那节的时候,了解到了memberwise和bitwise两种拷贝方式,其对应的就是深拷贝与浅拷贝,因此今天搜搜资料,总结一下笔记。

简单来说,两者的异同如下:

  • 对于简单对象(int,char,或者不含指针成员的自定义对象)来说,深拷贝和浅拷贝的效果都是一样的,都是开辟一块新的内存空间,来存放副本。

  • 而对于含有指针成员的自定义对象来说,浅拷贝和深拷贝之间就有不同了。若我们没有为该对象定义拷贝构造函数,那么编译器会构造一个默认拷贝构造函数,并在拷贝对象时调用该函数,此时进行的是浅拷贝,即直接拷贝指针内容(即一个地址值),而非拷贝指针所指的对象。此时就导致有两个指针指向同一内存区域,因此在析构的时候,会对该内存区域析构两次,会报错。而深拷贝就不一样了,深拷贝需要我们自己定义拷贝构造函数,然后开辟出一块新的内存空间来放置 拷贝方 的指针成员所指向的对象。如下:

    Student::Student(const Student &s){
        name = new char(20);	// char *name
        memcpy(name, s.name, strlen(s.name));
    }
    

    此时,names.name两个指针指向的是两个不同的内存地址。

在Python中,copy()方法和deepcopy()方法实现了浅拷贝和深拷贝。

针对Python中简单对象的复制,copy()deepcopy()没有什么区别,就是和大家通常理解的复制是一样的,在内存中新开辟一个空间,将原来地址中的数据拷贝到新的地址空间中。说明一下:我们这里所说的简单对象可以理解为最常见的对象,不包含的子对象的对象,也就是包含普通元素(数字,字符串)的对象。

而对于复杂对象的复制中,复杂对象可以理解为另外包含其他简单对象的对象,也就是包含子对象的对象,例如:List中嵌套List,或者Dict中嵌套List等,深拷贝和浅拷贝就不同了。若使用.copy()来拷贝的话,仅仅是拷贝了子对象的地址,而非对象本身,只有用深拷贝.deepcopy(),才能真正地拷贝子对象,其的差异见如下这个图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HUIrwKK2-1648435456424)(C:\Users\PrinceAlLHH\AppData\Roaming\Typora\typora-user-images\image-20211209224950146.png)]

注意

  • C++中,对于含有自定义成员对象的类时,是按照递归的方式进行一个memberwise拷贝。

  • 在Python中,没有指针的定义,但有引用的定义,我们可以直接将 Python 中的一个 list 当作指针, 所以和C++的一样,当对象中含指针成员时,就不能用浅拷贝。

  • python中引用的含义:

    list的引用,指的是列表的地址,并不是列表的内容。对于含有listlist,或含有listdict,都要使用deepcopy()来拷贝,不然只会拷贝到内嵌list的引用

    dict的引用,指的是字典的地址,并不是字典的内容。对于还有dict的列表,或含有dictdict,都要使用deepcopy()来拷贝,不然只会拷贝到内嵌dict的引用,如下:

    import copy
    
    if __name__ == "__main__":
        a = dict(name='wyuheng', age=22)
        b = dict(hight='181')
        c = [a, b]
        d = copy.copy(c)
    
        print(c[0] is d[0])
    
        d[0]["name"] = 'hezeli'
    
        print(c[0])
    

    输出为:

    True
    {'name': 'hezeli', 'age': 22}
    

    可看出,拷贝出的d[0]和c[0]指向的是同一块内存,所以,改变d[0],也会改变c[0]

参考文章

文章一

文章二

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值