深拷贝和浅拷贝有什么区别?
struct sample
{
char * ptr;
}
void shallowcpy(sample & dest, sample & src)
{
dest.ptr=src.ptr;
}
void deepcpy(sample & dest, sample & src)
{
dest.ptr=malloc(strlen(src.ptr)+1);
memcpy(dest.ptr,src.ptr);
}
浅复制不会创建新引用,但深复制会创建新引用。
下面是一个程序来解释深复制和浅复制。
public class DeepAndShollowCopy {
int id;
String name;
List<String> testlist = new ArrayList<>();
/*
// To performing Shallow Copy
// Note: Here we are not creating any references.
public DeepAndShollowCopy(int id, String name, List<String>testlist)
{
System.out.println("Shallow Copy for Object initialization");
this.id = id;
this.name = name;
this.testlist = testlist;
}
*/
// To performing Deep Copy
// Note: Here we are creating one references( Al arraylist object ).
public DeepAndShollowCopy(int id, String name, List<String> testlist) {
System.out.println("Deep Copy for Object initialization");
this.id = id;
this.name = name;
String item;
List<String> Al = new ArrayList<>();
Iterator<String> itr = testlist.iterator();
while (itr.hasNext()) {
item = itr.next();
Al.add(item);
}
this.testlist = Al;
}
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("Java");
list.add("Oracle");
list.add("C++");
DeepAndShollowCopy copy=new DeepAndShollowCopy(10,"Testing", list);
System.out.println(copy.toString());
}
@Override
public String toString() {
return "DeepAndShollowCopy [id=" + id + ", name=" + name + ", testlist=" + testlist + "]";
}
}
除其他答案外,
我从以下内容中了解到:
浅复制将对象的值类型(int, float, bool)字段复制到目标对象中,而对象的引用类型(string, class等)则作为引用复制到目标对象中。在这种情况下,目标引用类型将指向源对象的内存位置。
深复制将对象的值类型和引用类型复制到一个完全新的目标对象副本中。这意味着值类型和引用类型都将分配一个新的内存位置。
摘自[博客]: http://sickprogrammersarea.blogspot.in/2014/03/technical-interview-questions-on-c_6.html
深复制指使用一个对象的内容来创建同一类的另一个实例。在深复制中,两个对象可能包含相同的信息,但目标对象将拥有其自己的缓存和资源。任何一个对象的销毁都不会影响剩余的对象。重载赋值运算符将创建对象的深复制。
浅复制将一个对象的内容复制到同一类的另一个实例中,从而创建镜像。由于直接复制引用和指针,两个对象将共享另一个对象的外部包含内容,因此具体情况难以预测。
解释:
使用复制构造函数只需成员逐个复制数据值即可。这种复制方法称为浅复制。如果对象是简单类,由内置类型组成且没有指针,那么这是可以接受的。该函数将使用对象的值和行为不会受到浅复制的影响,只是成员指针的地址被复制而不是指针指向的值。该对象的数据值将被无意中更改。当函数超出作用域时,具有其所有数据的对象的副本将从堆栈中弹出。
如果对象有任何指针,则需要执行深复制。对于对象的深度复制,会在自由存储器中为对象分配内存,并复制指向的元素。深复制用于从函数返回的对象。
浅复制是创建一个新对象,然后将当前对象的非静态字段复制到新对象中。如果字段是值类型,则执行位按位复制;对于引用类型,则复制引用但不复制所指对象;因此原始对象和其克隆体引用同一对象。
深复制是创建一个新对象,然后将当前对象的非静态字段复制到新对象中。如果字段是值类型,则执行位按位复制。如果字段是引用类型,则执行所指对象的新副本。要克隆的类必须标记为[Serializable]。
复制数组:
数组是一个类,这意味着它是引用类型,因此array1 = array2会导致两个变量引用同一个数组。
但看看这个例子:
static void Main()
{
int[] arr1 = new int[] { 1, 2, 3, 4, 5 };
int[] arr2 = new int[] { 6, 7, 8, 9, 0 };
Console.WriteLine(arr1[2] + " " + arr2[2]);
arr2 = arr1;
Console.WriteLine(arr1[2] + " " + arr2[2]);
arr2 = (int[])arr1.Clone();
arr1[2] = 12;
Console.WriteLine(arr1[2] + " " + arr2[2]);
}
浅克隆意味着只复制克隆数组所表示的内存。
如果数组包含值类型对象,则会复制这些值;
如果数组包含引用类型,则只会复制引用 - 因此结果是有两个数组成员引用相同的对象。
要创建深层副本 - 其中引用类型被复制,必须循环遍历数组并手动克隆每个元素。
为了更加混淆浅拷贝和仅将新的变量名分配给列表之间的区别,我们只需再添加一点内容。
“假设我们有:
x = [
[1,2,3],
[4,5,6],
]
这个语句创建了3个列表:2个内部列表和一个外部列表。然后以变量名x的形式提供对外部列表的引用。如果我们执行
y = x
没有数据被复制。我们仍然在内存中有相同的3个列表。所有这些只是使外部列表在其先前名称x之外,也可用名称y访问。如果我们执行
y = list(x)
或者
y = x[:]
这将创建一个与x具有相同内容的新列表。列表x包含对2个内部列表的引用,因此新列表也将包含对这些相同2个内部列表的引用。只复制了一个列表——外部列表。 现在内存中有4个列表,两个内部列表、外部列表和外部列表的副本。原始外部列表可在名称为x下使用,而新的外部列表可在名称为y下使用。
内部列表没有被复制!此时您可以从x或y访问和编辑内部列表!
如果您有一个二维(或更高)列表或任何类型的嵌套数据结构,并且想要完全复制所有内容,则应使用copy模块中的deepcopy()函数。您的解决方案也适用于2-D列表,因为它遍历外部列表中的项目并复制每个项目,然后为所有内部副本构建一个新的外部列表。
MessageBox.Show(arr1[2] + " " + arr2[2]); arr2 = arr1; MessageBox.Show(arr1[2] + " " + arr2[2]); arr1[2] = 12; MessageBox.Show(arr1[2] + " " + arr2[2]); }`
- DeanOC