【问题标题】:How does an array in swift deep copy itself when copied or assigned复制或分配时,数组如何快速深度复制自身
【发布时间】:2019-07-18 11:44:30
【问题描述】:

我们都知道swift中的数组是值类型,这意味着在复制或分配一个数组后,修改新数组不会影响旧数组。如:

var a = ["a", "b", "c", "d", "e"]
var b = a
b[0] = "1"
print(a[0]) // a
print(b[0]) // 1

但我想知道数组怎么会这样工作。 'var' 数组的长度是动态的。通常我们必须分配一些堆内存来包含所有的值。我确实偷看了一些 struct Array 的源代码,数组的下划线缓冲区是使用类实现的。但是当复制一个包含类或内存指针成员的结构时,类和分配的内存默认不会复制。

那么一个数组在复制或分配给另一个缓冲区时如何复制它的缓冲区呢?

【问题讨论】:

标签: swift


【解决方案1】:

任何struct(如Array)的赋值都会导致结构内容的浅拷贝。 Array 没有特殊行为。存储Array 元素的缓冲区实际上并不是结构的一部分。指向该缓冲区的指针,存储在堆中,Array 结构的一部分,这意味着在分配时,缓冲区指针被复制,但它仍然指向同一个缓冲区。

Array 上的所有变异操作都会检查缓冲区是否被唯一引用。如果是,则算法继续。否则,创建缓冲区的副本,并将指向新缓冲区的指针保存到该Array 实例,然后算法如前所述继续。这称为写时复制 (CoW)。请注意,它不是所有值类型的自动功能。它只是一些标准库类型(如ArraySetDictionaryString 等)的手动实现功能。您甚至可以为自己的类型自己实现它。

当发生 CoW 时,它进行任何深度复制。它将复制值,这意味着:

  • 对于值类型(structenum、元组),值是struct/enum/元组本身。在这种情况下,深拷贝和浅拷贝是一回事。
  • 在引用类型 (class) 的情况下,被复制的值是 reference引用的对象没有被复制。旧引用和复制引用都指向同一个对象。因此,这是一个浅拷贝。

【讨论】:

  • 我认为这个答案是正确的,但高度特定于编译器。在 Swift 4.2 中,结构通常似乎以这种方式进行了优化,但旧版本总是复制结构,您必须根据需要自行实现写入时复制。
  • @AndreasOetjen 仍然如此。 Copy-on-write 是Array 的“手动实现”功能,并非所有struct 都通用。啊,我明白了,我有点不清楚。现在修复它
  • 是否应该使用函数isKnownUniquelyReferenced来实现写时复制功能?还是有其他更好的方法来检查引用是否唯一?
  • @NewSelf 这是我所知道的唯一一个。你觉得不够吗?
猜你喜欢
  • 1970-01-01
  • 2019-04-14
  • 1970-01-01
  • 1970-01-01
  • 2016-09-21
  • 1970-01-01
  • 2014-11-03
  • 2014-09-26
  • 1970-01-01
相关资源
最近更新 更多