当前位置: 首页 > 知识库问答 >
问题:

swift是否对所有结构进行写入复制?

薛飞星
2023-03-14

我知道swift会对数组进行优化,以便在写时复制,但它会对所有结构都这样做吗?例如:

struct Point {
   var x:Float = 0
}

var p1 = Point()
var p2 = p1 //p1 and p2 share the same data under the hood
p2.x += 1 //p2 now has its own copy of the data

共有1个答案

水渊
2023-03-14

数组是用写时复制行为实现的--无论编译器优化与否,您都可以得到它(当然,优化可以减少需要进行复制的情况)。

在基本级别上,array只是一个结构,它保存对包含元素的堆分配缓冲区的引用,因此多个array实例可以引用同一个缓冲区。当您要对给定的数组实例进行变异时,实现将检查缓冲区是否被唯一引用,如果是,则直接对其进行变异。否则,数组将执行基础缓冲区的复制,以便保留值语义。

但是,对于point结构,您并没有在语言级别上实现写时复制。当然,正如@Alexander所说,这并不能阻止编译器执行各种优化,以最小化复制整个结构的成本。不过,这些优化不必遵循写时复制的确切行为--只要程序按照语言规范运行,编译器就可以自由地做任何它想做的事情。

如果它们是函数中的局部变量,例如:

struct Point {
    var x: Float = 0
}

func foo() {
    var p1 = Point()
    var p2 = p1
    p2.x += 1
    print(p2.x)
}

foo()

编译器一开始甚至不必创建两个point实例--它只需创建一个初始化为1.0的浮点局部变量,并将其打印出来。

将值类型作为函数参数传递,对于足够大的类型和(在结构的情况下)充分利用其属性的函数,编译器可以通过引用而不是复制来传递它们。然后,只有在需要时,例如需要使用可变副本时,被调用方才能创建它们的副本。

在其他结构通过值传递的情况下,编译器也可以专门化函数,以便只跨函数所需的属性进行复制。

对于以下代码:

struct Point {
    var x: Float = 0
    var y: Float = 1
}

func foo(p: Point) {
    print(p.x)
}

var p1 = Point()
foo(p: p1)

假设编译器没有内联foo(p:)(在本例中是内联的,但是一旦其实现达到一定大小,编译器就会认为不值得)-编译器可以将函数专门化为:

func foo(px: Float) {
    print(px)
}

foo(px: 0)
 类似资料:
  • 问题内容: 我知道swift会优化写入时复制数组,但是会为所有结构执行此操作吗?例如: 问题答案: 为 实现 与写入时复制行为-你会得到它无论任何编译器的优化的(尽管当然,最佳化可以减少其中一个副本需要发生的病例数)。 从根本上讲,这只是一个对包含元素的堆分配缓冲区的引用的结构-因此,多个实例可以引用 同一 缓冲区。当您要更改给定的数组实例时,实现将检查缓冲区是否被唯一引用,如果是,则直接对其进行

  • 假设我想按x坐标对数组进行排序。 我怎么才能做到这一点?

  • 问题内容: 我遇到了以下SYBASE SQL: 该SQL的结果是 这看起来像是将HAVING条件应用于行而不是组。有人可以帮我指出描述这种情况的地方是Sybase 15.5文档吗?我所看到的只是“在团队中运作”。我在文档中看到的最接近的是: hading子句可以包括不在选择列表中且不在group by子句中的列或表达式。 (从这里引用)。 但是,他们没有完全解释当您这样做时会发生什么。 问题答案:

  • 我正在编写一个带有事务回滚的简单json数据库。我需要向一个文件追加一行文本,然后根据追加是否成功,将成功或失败记录到另一个文件。如果需要,第二个文件用于回滚。因此,在继续之前,我需要确定写操作是否成功。 我使用stream.write追加我的文本行,其中包括一个回调,应该验证写操作的成功或失败。 然后我在下面的URL上的NodeJS文档中读到了这个不幸的消息https://nodejs.org/

  • 问题内容: 如何将所有从mysql_query的行添加到mysql_fetch_array()?我希望能够尽可能有效地执行此操作,因为它可以处理很多行。 问题答案: 最常见的方式: 如文档中的示例所示。

  • 我目前正在研究一些工作中的想法,我有一个想法需要帮助。 我有一堆函数对象(想想像神经网络这样昂贵的东西)。它们以不同的间隔应用于线性缓冲区(比如一个由浮点或字节组成的数组)。所以它们看起来是这样的(把Start和End想象成“将对象应用到buf[开始:结束]”): 可能会有一些跳过(例如,参见C的开头vs B的结尾) 间隔肯定会有变化,无论是正的还是负的(例如,B可能会从变为。 当这种情况发生时,