有人可以提供一个需要浅拷贝的情况的例子吗?
请注意,在某些情况下,浅拷贝和深拷贝是相同的。当对象没有对其任何子变量的所有权时,就会发生这种情况;也就是说,所有子变量都是aggregated。我希望看到一个对象来自它所拥有的变量composed的示例,并且仍然希望将它们浅浅地复制。
备注:我不关心给出示例的语言。我从C ++ / Java / C#的角度提出这个问题,尽管我认为复制是一种与语言无关的概念。
答案 0 :(得分:8)
当拥有的变量是不可变类型时,浅拷贝就足够了。可以进行深层复制,但只会导致额外的内存使用。
答案 1 :(得分:4)
一个可能的用例是组合对象可以从浅拷贝中存在的状态信息派生,例如,您希望序列化您的对象。
您可以存储浅拷贝,然后在反序列化时从状态重建完整对象。
答案 2 :(得分:4)
来自C ++ POV,有一种情况我会使用浅拷贝:实现写时复制机制。
答案 3 :(得分:3)
class Element{
}
class Example {
private List<Element> elementList = new ArrayList<Element();
public List<Element> getElementList() {
return new ArrayList<Element>(this.elementList);
}
public void addElement(Element e) {
elementList.add(e);
}
public void removeElement(Element e) {
elementList.remove(e);
}
}
您希望Example.elementList
的所有修改都可以通过对象方法完成,但是您希望公开存储在列表中的元素。所以你创建了一个返回浅拷贝的getter。复制,因为您不希望调用者修改对象的列表和浅层,因为您希望从列表中公开对象,而不是它们的副本。
答案 4 :(得分:3)
如果你看一下Gang of Four设计模式,就会出现一种名为FlyWeight的模式。以下是维基百科的引用:
flyweight是一个对象 通过共享来最小化内存使用 尽可能多的数据与其他 类似的对象;这是一种使用方式 一个简单的大量对象 重复表示将使用 不可接受的记忆量。
这是浅层副本的可接受用途。
答案 5 :(得分:2)
正如我在回答你的相关问题时指出的那样,许多语言都没有浅层和深层复制的概念。但是,C ++中的这个类阻止你使用NULL指针,这可能是需要“浅”副本的例子:
template <typename T>
struct NotNull {
T * p;
NotNull( T * t ) : p( t ) {}
T & operator *() {
if ( ! p ) {
throw "null!";
}
return * p;
}
};
该类不拥有指向的东西,因此不应该复制。
答案 6 :(得分:2)
我对此的看法是,对于C ++与Java,使用深层复制的情况不同。
在C ++中,您可以使用深度复制来避免困难的内存管理问题,或者更容易实现多线程应用程序。
在Java中,由于这些原因,不需要深度复制。由于语言都是垃圾收集的,因此没有必要通过箍来释放数据结构。因此,不需要深层复制来简化问题。类似地,Java内置支持将多个线程的访问同步到共享数据结构。
在大多数情况下,假设您的应用程序的数据结构设计得很好,Java中不需要深度复制。
答案 7 :(得分:1)
较浅的副本可以更快地制作,这通常是出于显而易见的原因。最浅层的复制显然只是对原始对象的引用的副本。如果您没有变异对象并且可以保证在使用它时不会以其他方式进行更改,那么副本越浅越好。
答案 8 :(得分:1)
备注:我不关心给出示例的语言。我从C ++ / Java / C#的角度提出这个问题,尽管我认为复制是一种与语言无关的概念。
我认为这在很大程度上取决于语言。
在C ++中,复制扮演的角色与Java / C#中扮演的角色截然不同。在C ++中,我想不出很多浅层复制有意义的情况。您通常只是创建对象的引用或指针。复制构造函数通常实现深层复制,因为在C ++中,对象获取其成员的所有权,并负责管理其生命周期。因为没有GC,所以这些所有权语义变得很重要,你不能只有两个对象指向第三个没有特别小心(他们是否使用引用计数来保持第三个存活?如果不是,那两个对象中的哪一个拥有它?)
我甚至会说“深”和“浅”副本之间的区别在C ++中并没有真正意义。副本会创建新创建的对象工作所需的所有内容。有时,它共享一些数据(通常是不属于任何一个对象的数据),因此它可能不是“真正的”深层副本“,但它也不浅,因为它的大小该类通常被复制。