【问题标题】:Does the shallow/deep-copy terminology apply for objects without references?浅/深拷贝术语是否适用于没有引用的对象?
【发布时间】:2020-11-07 10:12:51
【问题描述】:

免责声明

这篇文章是关于“浅拷贝”和“深拷贝”这两个术语的正确用法,特别是在谈到复制一个不包含任何引用的对象时。这个问题并不意味着(也不应该)基于意见,除非关于这个话题确实没有达成共识。我已将此问题标记为 C,但它可能与语言无关,除非这些术语在该上下文中的含义已针对特定语言而非其他语言明确定义。

前言

术语“浅拷贝”和“深拷贝”通常用于复制带有引用的对象,以指定副本是否完整(独立于原始副本) .

但是,我也看到了在复制没有引用的对象时使用的这个术语,其中两个术语的含义完全相同,无需区分。到目前为止,我还没有找到一个简洁的定义来涵盖这些术语的这种特殊用途。

  • Stack Overflow 上给出的定义(在标签shallow-copydeep-copy 中):

    浅拷贝包含指向原始变量的链接(内存中的地址)。浅拷贝上的更改会反映在源对象上。

    深拷贝复制指向的对象或变量,以便目标(被分配的对象)接收自己的本地副本。

    根据这些定义,没有引用的对象副本将是深层副本。

  • 维基百科上给出的定义(在文章Object copying中):

    复制对象的一种方法是浅拷贝。在这种情况下,将创建一个新对象 B,并将 A 的字段值复制到 B。这也称为逐字段复制、逐字段复制或字段复制。如果字段值是对对象的引用(例如,内存地址),它会复制该引用,因此引用与 A 相同的对象,如果字段值是原始类型,它会复制原始类型的值。在没有原始类型的语言中(一切都是对象),副本 B 的所有字段都是对与原始 A 的字段相同的对象的引用。因此,引用的对象是共享的,因此如果修改了这些对象之一(来自 A或 B),更改在另一个中可见。浅拷贝很简单而且通常很便宜,因为它们通常可以通过简单地精确复制位来实现。

    另一种方法是深度复制,这意味着取消引用字段:不是复制对对象的引用,而是为任何引用的对象创建新的复制对象,并将对这些对象的引用放在 B 中。结果与结果不同 a浅拷贝给出了副本 B 引用的对象与 A 引用的对象不同,并且是独立的。由于需要创建额外的对象,深拷贝更昂贵,并且由于引用可能形成复杂的图,因此可能会更加复杂。

    根据这些定义,没有引用的对象副本将是浅拷贝。

我认为这两个术语都不合适,因为“浅拷贝”意味着拷贝不完整,而“深拷贝”意味着拷贝需要某种特殊处理(或高成本)。 由于复制没有引用的对象既完整又不需要任何特殊处理,我认为这些术语都不应该使用。然而,这篇文章不是关于我的想法,而是编程社区当前的共识(如果有的话)。

问题

当我复制一个没有引用的对象时,会被考虑

  • 浅拷贝(因为不涉及引用)?
  • 深拷贝(因为目标对象独立于源对象)?
  • 两者都有?
  • 也没有?

部分深拷贝有什么好的术语,其中一些字段是浅拷贝的,而另一些是深拷贝的?

【问题讨论】:

  • 你复制了所有的指针,你也没有复制任何指针,所以两者都是。
  • Wikipedia 上的定义... 你搞错了。维基百科对于提供描述或示例等事情很有用。将其视为权威是一个巨大的错误......
  • 该术语不是“简单”或“复杂”对象,相关术语是组合或聚合。您只能执行聚合的深层复制(无论成员是嵌入还是引用),而您可以对组合执行浅层、写入时复制或急切的深层复制。
  • @AndrewHenle,虽然我同意在依赖维基百科时需要有一定的酌处权,但我发现问题中提出的特定引文很好地定义了术语“浅拷贝” ”和“深拷贝”与我对它们的理解一致。我认为这些术语的当前 SO 标签信息具有误导性。
  • 注意:我为深拷贝和浅拷贝更新了标签 wiki。希望它们不再与 Wikipedia 文章(深拷贝标签 wiki 已经提到,浅拷贝现在也提到)显示出看似不一致的地方。

标签: c terminology deep-copy shallow-copy


【解决方案1】:

当区分不适用时,只需将其称为“副本”。它不是浅拷贝,因为没有共享引用,也不是深拷贝,因为只复制了结构中的值。

这个问题就像问岩石是否是无神论者。当然,他们不是有神论者。但是有神论者/无神论者的区别真的适用于他们吗?有些天平只为测量某些事物而设计。

【讨论】:

  • 此外,认识到出于分类目的,在没有区别的情况下,任何副本都必然深又浅。
  • @JohnBollinger 除非您将浅定义为“不深”,将深定义为“不浅”,否则两者都不是。
  • 这是一种有趣的思考方式,它证实了我个人对此事的看法。我曾希望有某种简洁的定义,但当这样考虑时,很明显不存在,因为这些术语在那种情况下没有意义。
  • 我非常不同意这个答案,因为除非我弄错了,否则@FelixG 不会询问浅拷贝/深拷贝的区别在只允许没有引用属性的对象的假设编程语言中是否有意义(类似以你的摇滚类比),在那种情况下当然没有意义。他在问这种区别在真正的编程语言中是否有意义(允许具有引用属性的对象)对于没有引用属性的特定对象。
  • ... 在这种情况下,这是有道理的,因为没有像 “复制”操作这样的东西。在大多数语言中,至少有两个“复制”操作,一个“浅复制”操作(clone-1)和一个“深复制”操作(clone-∞),有些语言提供了其他clone-k 操作,例如 Smalltalk,它也提供了 clone-2 操作。因此,您可以将没有引用属性的对象上的操作松散地称为“复制”,但这不是语言的操作,因此准确地说,您应该将其称为“浅复制”或“深复制”,即使在这种情况下,目标对象是相同的。
【解决方案2】:

Peter Grogono 和 Markku Sakkinen 于 2000 年发表的论文Copying and Comparing: Problems and Solutions 是您提出问题的一个很好的参考。

各种复制操作可以应用于源表达式目标表达式

  • assignment(也称为aliasing),将目标表达式绑定到源表达式的位置;
  • replacement(也称为mutation),将源表达式的内容复制到目标表达式的位置;
  • 克隆,将目标表达式绑定到新位置并将源表达式的内容复制到该新位置,即执行分配后替换。

在下图中,箭头表示绑定,方框表示位置,XYZ表示名称, AA′BB′代表值, • 代表引用,第一个函数参数代表目标表达式和第二个函数参数代表源表达式。

替换和克隆可以根据它们的深度进一步分类:

  • 浅层操作,复制值和引用;
  • 深度操作,复制值并对引用执行深度操作。

浅层和深层操作之间的区别不适用于赋值。浅克隆和深克隆通常分别称为浅拷贝深拷贝

由于深度是无限的,所以除了浅层和深层之外,实际上还有无限的替换和克隆操作。

我们可以定义replace-k,一个替换深度k,如下:

  • replace-0(X, Y) 执行assign(X, Y);
  • replace-k(X, Y) for k > 0 复制 的值YX 的位置,并从 Y 的引用执行替换-(k - 1) 到 Y 的位置em>X.

我们可以定义clone-k,一个深度为k的克隆,如下:

  • clone-0(X, Y) 执行assign(X, Y);
  • clone-k(X, Y) for k > 0 绑定 X em> 到一个新位置,将 Y 的值复制到该新位置,并从 Y的引用中执行 clone-(k - 1) > 进入那个新位置。

提供克隆操作的语言通常只提供clone-1(浅拷贝)和clone-∞(深拷贝)。

现在我们已经提供了定义,让我们来解决您的问题。

当我复制一个没有引用的对象时,会被考虑

  • 浅拷贝(因为不涉及引用)?
  • 深拷贝(因为目标对象独立于源对象)?
  • 两者都有?
  • 也没有?

这取决于谁在考虑 k0 ≥ 1 的 clone-k0 操作已应用于源对象:

  • 如果是调用者考虑的,他已经知道自己对源对象应用了哪个操作,所以解决方法是:{clone-k0}。
  • 如果是别人考虑的,只能通过比较源对象和目标对象的结构来猜测调用者可能对源对象应用了哪个操作,所以解决方法是:{clone-1, clone -2, ..., 克隆-∞}。

部分深拷贝有什么好的术语,其中一些字段是浅拷贝的,而另一些是深拷贝的?

据我所知,这种复制通常更有用,因为它是语义的,而浅复制和深复制是句法。所以我称之为语义复制,正如论文所暗示的那样:

浅层和深层操作通常没有用。在大多数情况下,“浅”太浅,“深”太深。为了普遍适用,复制操作应该尊重对象的语义属性,而不仅仅是它们的句法属性。

【讨论】:

  • 但是这两个操作都减少为值属性的副本这一事实难道不能仅仅意味着这两个术语都不适用(如另一个答案中所述)吗?毕竟,如果两者是等价的,那么为什么要使用其中任何一个术语(而不仅仅是“复制”)?
  • @FelixG 您可以使用“复制”一词,但这不是一个单一的克隆操作,它是一组无限的克隆操作:{clone-k | N} 中的 k。所以不,“浅拷贝”和“深拷贝”这两个术语都适用,因为它们是解决方案。例如。方程 x ^2 = 4 的 R 中的解是 {−2, 2} 中的 x 我们不会这么说 - 2 和 2 不适用。类似地,方程 f (obj-without-ref) = obj-without-ref 的 {shallow copy, deep copy} 中的解是 {shallow copy 中的 f , 深拷贝},我们并不是说浅拷贝和深拷贝不适用。
  • @FelixG 我刚刚更新了我的帖子,以便更好地回答您的问题。
猜你喜欢
  • 1970-01-01
  • 2017-08-30
  • 1970-01-01
  • 2012-04-12
  • 2012-05-26
  • 2012-02-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多