swift - Swift 中 “+=” 运算符的内存安全

标签 swift inout memory-safety

我一直在学习swift,遇到了一个关于内存安全的问题。 += 运算符采用左侧的 inout 参数,该参数应对整个函数调用具有写访问权限。它在其实现中执行类似 left = right+left 的操作。这似乎是写入和读取访问的重叠。这怎么不违反内存安全呢?

编辑: 根据The Swift Programming Language ,它可以发生在单个线程中:

However, the conflicting access discussed here can happen on a single thread and doesn’t involve concurrent or multi-threaded code.

详细说明: 以下是《Swift 编程语言》(Swift 4.1 beta)中的两个示例。我很困惑如何在结构 Vector2D 中实现此自定义 +=没问题:

static func += (left: inout Vector2D, right: Vector2D) {
    left = left + right
}

当这不是:

var stepSize = 1
func incrementInPlace(_ number: inout Int) {
    number += stepSize
}
incrementInPlace(&stepSize)
// Error: conflicting accesses to stepSize

进一步编辑:

我认为我的问题确实是 += 作为一个函数,特别是在使用时

stepSize += stepSize

或者使用自定义实现:

var vector = Vector2D(x: 3.0, y: 1.0)
vector += vector

这没有任何错误。但是 func 从左侧获取输入,因此可以对“step”进行长期写入访问,那么如果右侧也传入“step”,我很困惑这为什么不是“step”的即时读取访问”与长期写的“步骤”重叠。或者,当您在同一个实例中传递两个 inout 参数,而不是一个 inout 和一个常规参数时,这只是一个问题吗?

最佳答案

我知道您已经明白了,但需要向 future 的读者进行澄清;在您的评论中,您说:

... it is, in the end, a problem with any one-line code changing self by reading self first.

不,仅此还不够。作为Memory Safety章节说,这个问题仅在以下情况下才会显现出来:

  • At least one is a write access.
  • They access the same location in memory.
  • Their durations overlap.

考虑:

var foo = 41
foo = foo + 1

foo = foo + 1 不是问题(foo += 1 也不会;foo += foo 也不会),因为构成一系列“瞬时”访问。因此,尽管我们有(用你的话来说)“通过首先读取 self 来更改 self 的代码”,但这不是问题,因为它们的持续时间不重叠。

只有当您处理“长期”访问时,问题才会显现出来。那样guide继续说道:

A function has long-term write access to all of its in-out parameters. The write access for an in-out parameter starts after all of the non-in-out parameters have been evaluated and lasts for the entire duration of that function call. If there are multiple in-out parameters, the write accesses start in the same order as the parameters appear.

One consequence of this long-term write access is that you can’t access the original variable that was passed as in-out, even if scoping rules and access control would otherwise permit it—any access to the original creates a conflict.

所以,考虑你的第二个例子:

var stepSize = 1
func incrementInPlace(_ number: inout Int) {
    number += stepSize
}
incrementInPlace(&stepSize)

在这种情况下,您可以长期访问任何number 引用。当您使用 &stepSize 调用它时,这意味着您可以长期访问与 stepSize 关联的内存,因此 number += stepSize 意味着您正在尝试访问 stepSize,而您已经拥有对它的长期访问权限。

关于swift - Swift 中 “+=” 运算符的内存安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49832784/

相关文章:

ios - iOS 11 用户是否可以通过部署目标 10.2 显示 ARSCNView?

ios - Geofire/火力基地.indexOn

Swift 类型约束没有按预期工作

swift - 如何将数组 block 传递给 inout 函数?类型删除?

c++ - C++中如何判断传入缓冲区是否有效?

ios - 通过一次滑动手势快速控制多个按钮

swift2 - 使用 inout 关键字 : is the parameter passed-by-reference or by copy-in copy-out (/call by value result)

Swift 泛型与任何泛型

c - 静态链接到C程序的Rust代码是否会因此获得任何有益的安全特性?