保证有关局部变量中引用寿命的信息 [英] Guarantees about the lifetime of a reference in a local variable

查看:145
本文介绍了保证有关局部变量中引用寿命的信息的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Swift 中,我可以使用 ARC 机制来管理进程外部资源的生存期,因为类的实例可以预知地被初始化.这与像 Java 运行时这样的环境形成对比,在运行时环境中,当垃圾收集器收集对象时实例会被取消初始化,这不能保证会在定义的时间窗口内发生.

In Swift, I can use the ARC mechanism to manage the lifetime of resources external to the process because instances of classes are de-initialized predictably. This is in contrast to environments like the Java Runtime where instances are de-initialized when the garbage collector collects the object, which is not guaranteed to happen in a defined time window.

但是,当实例被局部变量引用时,Swift语言和运行时对实例的生存期的确切保证是什么?例如.当局部变量持有对该实例的唯一引用时,实例可以被重新分配的最早时间是什么?

But what are the exact guarantees that the Swift language and runtime make about the lifetime of instances when those instances are referenced by local variables? E.g. what is the earliest point that an instance may be deallocated, when a local variable is holding the only reference to it?

在下面的示例中,我正在创建一个类的实例,并将对它的引用存储在局部变量中.

In the following example, I am creating an instance of a class and store a reference to it in a local variable.

public final class Something {
    init() { print("something.init()") }
    deinit { print("something.deinit()") }
}

func useSomething() {
    let something = Something()
    print("useSomething()")
}

useSomething()

在我打印useSomething()的点之后不使用该变量,但是deinit始终在 之后运行,并调用print():

The variable is not used after the point where I print useSomething() but deinit runs consistenly after that call to print():

$ swift run -c release
something.init()
useSomething()
something.deinit()

似乎引用总是在变量超出范围时递减.将变量声明包装在do块中会更改顺序:

It seems that references are always decremented at the point where the variable goes out of scope. Wrapping the variable declaration in a do block changes the order:

func useSomething() {
    do { let something = Something() }
    print("useSomething()")
}

$ swift run -c release
something.init()
something.deinit()
useSomething()

此顺序是否得到保证,或者可以使用其他编译器或优化级别进行更改?

Is this order guaranteed or can it change with a different compiler or optimization level?

我对此感兴趣的原因是,我想将C API包装在面向对象的Swift API中,并希望使用Swift类和引用计数自动管理使用C API分配的资源的生命周期.如果每次使用C API都需要引用对其操作的资源,则这样做非常有用,因为我知道Swift实例将至少在对实例所代表的资源进行的最后一次调用之前一直存在.

The reason I'm interested in this is that I want to wrap C APIs in object-oriented Swift APIs and would like to automatically manage the lifetime of resources allocated using a C API using Swift classes and reference counting. This works great if every usage of the C API requires a reference to the resource it operates on because I know that the Swift instance will live at least until the last call that operates on the resource that instance is representing.

但是某些API使用全局状态来选择资源,并且对该API的后续调用不需要引用要传递的资源,而是隐式地对所选资源进行操作. OpenGL的glDrawElements()隐式使用了大约5或10个这样的资源(顶点数组,着色器,帧缓冲区,纹理...).

But some APIs use global state to select a resource and subsequent calls to the API do not require a reference to the resource to be passed and implicitly operate on the selected resource instead. OpenGL's glDrawElements() implicitly uses maybe 5 or 10 such resources (vertex arrays, shaders, frame buffers, textures …).

推荐答案

Swift不能保证对象的生存期,直到 最接近的范围的末端,例如 Swift论坛中的以下主题:

Swift makes no guarantee about the the lifetime of an object until the end of the closest surrounding scope, see for example the following threads in the Swift Forum:

  • Should Swift apply "statement scope" for ARC
  • ARC // Precise Lifetime Semantics

在声明处可以使用 withExtendedLifetime(_:_:) :

where it is stated you can use withExtendedLifetime(_:_:):

在评估闭包的同时确保闭包返回之前不会破坏给定实例.

Evaluates a closure while ensuring that the given instance is not destroyed before the closure returns.

为此目的.至于理由 戴夫·亚伯拉罕(Apple)状态:

for that purpose. As for the rationale, Dave Abrahams (Apple) states:

缺乏这样的保证,实际上很少有用 无论如何,是什么使我们能够制作昂贵的副本(以及相关的 刷新流量,通常是CoW分配和复制辐射) 动作,实际上是免费的.采用它基本上会杀死我们的 CoW的性能故事.

The lack of such a guarantee, which is very seldom actually useful anyhow, is what allows us to turn costly copies (with associated refcount traffic and, often CoW allocation and copying fallout) into moves, which are practically free. Adopting it would basically kill our performance story for CoW.

乔·格罗夫(Apple) 在同一线程中:

是的,如果您想将对象管理的资源出售给该对象之外的使用者,则需要使用withExtendedLifetime来使对象保持活动状态,直到您使用资源为止.对此建模的一种更干净的方法可能是将类或协议置于控制对文件句柄处理I/O的位置,而不是自动出售文件句柄,以使所有权语义更自然地出现:

Yeah, if you want to vend resources managed by an object to consumers outside of that object like this, you need to use withExtendedLifetime to keep the object alive for as long as you're using the resources. A cleaner way to model this might be to put the class or protocol in control of handling the I/O to the file handle, instead of vending the file handle itself, so that the ownership semantics fall out more naturally:

这篇关于保证有关局部变量中引用寿命的信息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆