`UnsafeMutablePointer.initialize()` 实际上是做什么的?

Cop*_*ash 5 c pointers ios automatic-ref-counting swift

以下是基于我的猜测。有人请指出我理解错误的部分。

如果我有一个类,其中一个实例占用 128 位,称为Class128Bits. 我的程序在 64 位计算机上运行。

首先,我调用let pointer = UnsafeMutablePointer<Calss128Bits>.allocate(capacity: 2) 内存布局应该是这样的:

000-063 064 bits chaos
064-127 064 bits chaos
128-255 128 bits chaos
256-383 128 bits chaos
Run Code Online (Sandbox Code Playgroud)

如果我调用pointer.pointee = aClass128Bits,它会崩溃,因为前两个网格中的指针尚未初始化。访问他们指向的内容会导致不可预测的结果。

但是如果我调用pointer.initialize(to: aClass128Bits, count: 2),指针可以像这样初始化:

000-063 address to offset 128
064-127 address to offset 256
128-255 a copy of aClass128Bits
256-383 a copy of aClass128Bits
Run Code Online (Sandbox Code Playgroud)

那么任何访问都是安全的。然而,这不能解释为什么UnsafeMutablePointer<Int>不崩溃。


原来的

我面临的情况: 碰撞

指向的指针Int工作正常,但指向String崩溃的指针。我知道我需要像这样初始化它: 不崩溃

但是我看不出我需要通过"42"两次的原因。在 C 中,我可能会做类似这样的事情:

char *pointer = (char *)malloc(3 * sizeof(char));
memcpy(pointer, "42", 3);
free(pointer)
Run Code Online (Sandbox Code Playgroud)

如果allocateequals mallocfreeequals deallocatememcpyequals pointee{ set },那么做什么initializedeinitialize实际做什么?为什么我的代码会崩溃?

OOP*_*Per 2

您需要的原因之一initialize(),也是目前唯一的原因,是

对于 ARC

在了解 ARC 的工作原理时,您最好考虑局部作用域变量:

func test() {
    var refVar: RefType = initValue  //<-(1)
    //...
    refVar = newValue //<-(2)
    //...
    //<-(3) just before exiting the loacl scope
}
Run Code Online (Sandbox Code Playgroud)

对于通常的赋值(2),Swift 生成如下代码:

swift_retain(_newValue)
swift_release(_refVar)
_refVar = _newValue
Run Code Online (Sandbox Code Playgroud)

(假设_refVar_newValue是非托管伪变量。)

Retain表示引用计数加1,release表示引用计数减1。


但是,想想当初始值分配如 (1) 时会发生什么。

如果生成通常的赋值代码,代码可能会在这一行崩溃:

swift_release(_refVar)
Run Code Online (Sandbox Code Playgroud)

因为为 var 新分配的区域可能会充满垃圾,因此swift_release(_refVar)无法安全执行。

用零(空)填充新区域并release安全地忽略空可能是一种解决方案,但它有点多余且无效。

因此,Swift 生成了这样的代码来进行初始值赋值:

(对于已经保留的值,如果您知道所有权模型,则由您拥有。)

_refVar = _initValue
Run Code Online (Sandbox Code Playgroud)

(对于未保留的值,意味着您还没有所有权。)

swift_retain(_initValue)
_refVar = _initValue
Run Code Online (Sandbox Code Playgroud)

这是initialize

不释放垃圾数据,并分配一个初始值,如果需要则保留它。

(上面对“通常赋值”的解释有点简化,Swiftswift_retain(_newValue)在不需要时省略。)


当在 (3) 处退出本地作用域时,Swift 只是生成这样的代码:

swift_release(_refVar)
Run Code Online (Sandbox Code Playgroud)

所以,这是deinitialize


当然,您知道像 、 等基本类型不需要保留和释放Int,因此对于此类类型initialize可能deinitialize需要保留和释放donothing

当你定义一个包含一些引用类型属性的值类型时,Swift 会生成initialize专门deinitialize针对该类型的过程。


局部作用域示例适用于在堆栈上分配的区域,而initialize()ofdeinitialize()UnsafeMutablePointer适用于在堆上分配的区域。

Swift 的发展如此之快,以至于您可能会找到另一个需要的原因,initialize()并且deinitialize()在将来,您最好让它成为一种习惯,initialize()并且所有类型的deinitialize()分配都是如此。UnsafeMutablePointerPointee