当前位置: 首页 > 面试题库 >

是否为所有结构写入时快速复制?

公羊曜灿
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

问题答案:

Array实现 与写入时复制行为-你会得到它无论任何编译器的优化的(尽管当然,最佳化可以减少其中一个副本需要发生的病例数)。

从根本上讲,Array这只是一个对包含元素的堆分配缓冲区的引用的结构-因此,多个Array实例可以引用 同一
缓冲区。当您要更改给定的数组实例时,实现将检查缓冲区是否被唯一引用,如果是,则直接对其进行更改。否则,数组将执行基础缓冲区的副本,以保留值的语义。

但是,根据您的Point结构,您不会在语言级别实现写时复制。当然,正如@Alexander所说,这不会阻止编译器执行各种优化以最大程度地减少复制整个结构的成本。但是,这些优化并不一定要遵循写时复制的确切行为-
只要程序根据语言规范运行,编译器就可以随意执行 任何 所需的操作。

在您的特定示例中,p1p2都是全局的,因此编译器需要使它们成为不同的实例,因为同一模块中的其他.swift文件可以访问它们(尽管可以通过优化整个模块来优化它们)。但是,编译器仍然不需要复制实例–它可以在编译时评估浮点加法,并使用初始化一个全局变量0.0,而使用初始化另一个全局变量1.0

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

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)

它仅将Pointx属性值传递给函数,从而节省了复制y属性的成本。

因此,编译器将尽其所能以减少值类型的复制。但是,由于在不同情况下有如此多的优化,您不能简单地将任意值类型的优化行为简化为写时复制。



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

  • 我需要一个支持以下操作的数据结构: 插入一个数字; 找到所有插入数字的中位数; (附加)找到所有插入数字的已知分位数(0-1); 最简单的方法是在每次插入后对数字进行排序,但这并不快速。有没有更快的解决方法?

  • 我从一段时间开始学习雨燕,我知道结构和阶级之间的区别。主要区别是结构是值型,类是引用型,但不明白什么时候用结构代替类。请解释一下。 例如,在协议的情况下: 其次,我们将类类型的协议如下所示: 所以,请解释我,当我们必须使用结构类型或类类型的协议。

  • 问题内容: 我正在尝试快速进行简单的DNS查找。到目前为止,这是我拥有的代码: 此时,“地址” NSArray中的每个元素都是一个CFDataRef对象,该对象包装了一个sockaddr结构。 由于CFDataRef可以免费连接到NSData,因此可以像这样循环遍历它们: 到目前为止,一切都很好(我认为)。当我在单元测试中运行时,这会打印出有效的外观数据。这是我被卡住的地方。为了我的一生,我不知道

  • 结构体 结构体 (struct) 是一种记录类型,所包含的每个域 (field) 都有一个名称。 每个结构体也都有一个名称,通常以大写字母开头,使用驼峰命名法。 元组结构体 (tuple struct) 是由元组和结构体混合构成,元组结构体有名称, 但是它的域没有。当元组结构体只有一个域时,称为新类型 (newtype)。 没有任何域的结构体,称为类单元结构体 (unit-like struct)

  • 这一章描述了一个非常简单的 Groovy 项目. 通常, 一个真正的项目要比这个复杂的多. 因为 Groovy 项目是一个 Java 项目, 任何你可以对 Java 项目做的配置也可以对 Groovy 项目做. Chapter 24,The Groovy Plugin有更加详细的描述, 你也可以在 samples/groovy 目录里找到更多的例子.