深复制vs.浅复制
- 浅复制:复制中把成员指针变量当成“指针”处理,赋值后两个指针指向相同的内存
- 深复制:复制中把指针成员变量当成“值”处理,赋值后指针指向对象副本(即两个指针指向的内存不同,但内存中内容相同)
C++中的复制
C++中的指针具有缺陷,无法保证指针指向的空间可用(C++从入门到段错误~~)当指针作为类成员时,应进行恰当的管理,
- 指针成员采取常规指针型行为。这样的类具有指针的所有缺陷但无需特殊的复制控制。
- 类可以实现所谓的“智能指针”行为。指针所指向的对象是共享的,但类能够防止悬垂指针。
- 类采取值型行为。指针所指向的对象是唯一的,由每个类对象独立管理。
tip
- 为了管理具有指针成员的类,必须定义三个复制控制成员:复制构造函数、赋值操作符和析构函数。这些成员可以定义指针成员的指针型行为或值型行为,也就是决定了复制的时候是深复制还是浅复制
OC的复制
集合的复制
不可变集合
- copy:指针复制。
cpy_arr == ori_arr
- mutableCopy:对象复制(单层深复制,对集合中的元素进行指针复制)
initWithArray:copyItems:YES
- 当集合元素可变时,对该元素进行对象复制;否则进行指针复制
- 返回
__NSArrayI *
arrayWithArray
对集合进行对象复制,对集合内元素进行指针复制
可变集合
- copy:对象复制
cpy_arr != ori_arr
- mutableCopy:对象复制(单层深复制,对集合中的元素进行指针复制)
initWithArray:copyItems:YES
当元素为可变时,复制该元素,不可变时,不复制- 返回
__NSArrayI *
- 当集合元素可变时,对该元素进行对象复制;否则进行指针复制
- 返回
arrayWithArray
对集合进行对象复制,对集合内元素进行指针复制 ###非集合对象 参考集合的复制(毕竟对象的实例变量也有可能是指针),主要考虑对象是否可变
tip
- 对于二维数组,即便使用
initWithArray:copyItems:YES
,对于数组的元素,也只是进行指针复制,亦即:arr_cpy != arr
arr_cpy[i] != arr[i]
arr_cpy[i][j] == arr[i][j]
- 若想完全实现深复制,可通过
NSKeyedArchiver
和NSKeyedUnarchiver
实现
Swift中的复制
- Swift中的字符串,数组,字典类型作为结构体被实现
- 当他们被赋值给一个新的常量/变量,或者作为实参被传递给函数或方法是,将被复制
- Swift内部管理所有的副本确保整体性能得到优化
pyhton中的复制
- 对对象赋值时,进行指针复制
aList=[[1, 2], 3, 4] b = a#id(b) == id(a)
- 切片,对所指指定的元素进行指针复制。
aList=[[1, 2], 3, 4]b = aList[:]#id(b) != id(a)#id(b[0]) == id(a[0])
- copy.copy 只拷贝父对象,不会拷贝对象的内部的子对象。
aList=[[1, 2], 3, 4]b = copy.copy(aList)#id(b) != id(a)#id(b[0]) == id(a[0])
- copy.deepcopy 拷贝对象及其子对象
aList=[[1, 2], 3, 4]b = copy.copy(aList)#id(b) != id(a)#id(b[0]) != id(a[0])
C#中的复制
MemberwiseClone
- MemberwiseClone 方法创建一个浅表副本
- 具体来说就是创建一个新对象,然后将当前对象的非静态字段复制到该新对象。如果字段是值类型的,则对该字段执行逐位复制。如果字段是引用类型,则复制引用但不复制引用的对象;因此,原始对象及其复本引用同一对象
实现完全深复制
- 借助.Net的序列化和反序列化机制,可以十分简单的深度Clone一个对象。
- 首先将对象序列化到内存流中,此时对象和对象引用的所用对象的状态都被保存到内存中。.Net的序列化机制会自动处理循环引用的情况。
- 然后将内存流中的状态信息反序列化到一个新的对象中。