gpt4 book ai didi

ios - `UnsafeMutablePointer.initialize()`到底是做什么的?

转载 作者:搜寻专家 更新时间:2023-10-31 22:20:22 26 4
gpt4 key购买 nike

以下是我的猜测。请大家指出我理解错误的部分。

如果我有一个类,其中一个实例占用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

如果我调用 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

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


原创

我面临的情况: Crash

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

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

char *pointer = (char *)malloc(3 * sizeof(char));
memcpy(pointer, "42", 3);
free(pointer)

如果allocate等于 malloc , free等于 deallocate , memcpy等于 pointee{ set } ,然后做什么initializedeinitialize实际上呢?为什么我的代码会崩溃?

最佳答案

let pointer0 = UnsafeMutablePointer<String>.allocate(capacity: 1)
let pointer1 = UnsafeMutablePointer<Int>.allocate(capacity: 1)

让我们检查两者的大小

MemoryLayout.size(ofValue: pointer0) // 8
MemoryLayout.size(ofValue: pointer1) // 8

让我们检查 .pointee 的值

pointer0.pointee // CRASH!!!

同时

pointer1.pointee // some random value

为什么?答案很简单。我们分配了 8 个字节,独立于“关联”类型。现在很清楚了,内存中的 8 个字节不足以存储任何字符串。必须间接引用底层内存。但是那里有大约 8 个随机字节......加载内存中的内容,地址由 8 个随机字节表示为字符串,很可能会崩溃:-)

为什么第二种情况没有崩溃? Int值是8字节长,地址可以用Int值表示。

让我们在 Playground 上试试

import Foundation

let pointer = UnsafeMutablePointer<CFString>.allocate(capacity: 1)

let us = Unmanaged<CFString>.passRetained("hello" as CFString)

pointer.initialize(to: us.takeRetainedValue())
print(pointer.pointee)

us.release()

// if this playground crash, try to run it again and again ... -)
print(pointer.pointee)

看看它给我打印了什么 :-)

hello
(
"<__NSCFOutputStream: 0x7fb0bdebd120>"
)

背后没有奇迹。 pointer.pointee 试图表示内存中的内容,哪个地址存储在我们的指针中,作为其关联类型的值。它永远不会为 Int 崩溃,因为内存中某处的每 8 个连续字节都可以表示为 Int。

Swift 使用 ARC,但创建 Unsafe[Mutable]Poiner 不会为 T 的实例分配任何内存,销毁它也不会为其释放任何内存。

类型化内存必须在使用前初始化,使用后反初始化。这是分别使用 initialize 和 deinitialize 方法完成的。只有非平凡类型才需要取消初始化。也就是说,包括去初始化是一种让代码面向 future 的好方法,以防您更改为不平凡的东西

为什么赋值给具有 Int 值的 .pointee 不会崩溃?

  1. 初始化存储值的地址
  2. 赋值给pointee更新存储地址的值

如果不初始化它很可能会崩溃,只是通过在某个随机地址处仅修改内存中的 8 个字节来降低概率。

试试这个

import Darwin
var k = Int16.max.toIntMax()
typealias MyTupple = (Int32,Int32,Int8, Int16, Int16)

var arr: [MyTupple] = []
repeat {
let p = UnsafeMutablePointer<MyTupple>.allocate(capacity: 1)
if k == 1 {
print(MemoryLayout.size(ofValue: p), MemoryLayout.alignment(ofValue: p),MemoryLayout.stride(ofValue: p))
}
arr.append(p.pointee)
k -= 1
defer {
p.deallocate(capacity: 1)
}
} while k > 0

let s = arr.reduce([:]) { (r, v) -> [String:Int] in
var r = r
let c = r["\(v.0),\(v.1),\(v.2),\(v.3)"] ?? 0
r["\(v.0),\(v.1),\(v.2),\(v.3)"] = c + 1
return r
}
print(s)

我收到了

8 8 8
["0,0,-95,4104": 6472, "0,0,0,0": 26295]
Program ended with exit code: 0

看起来不是很随意,是吗?这就解释了为什么指向 Int 的类型化指针发生崩溃的可能性很小。

关于ios - `UnsafeMutablePointer.initialize()`到底是做什么的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39716984/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com