如何在Swift 3中使用UnsafeMutablePointer<T?>?

3

我是Swift的新手,不太明白如何使用UnsafeMutablePointer<T?>。有人可以帮助我吗?

struct TestStruct {
    var a = 0
}

func foo(ptr: UnsafeMutablePointer<TestStruct?>?) {
    ptr?.pointee?.a = 123 // pointee is nil, but why?
}

func bar(ptr: TestStruct?) {
    print("hello: \(ptr?.a)") // hello: nil
}

var ref = UnsafeMutablePointer<TestStruct?>.allocate(capacity: 1)

foo(ptr: ref)
bar(ptr: ref.pointee)

ref.deallocate(capacity: 1)

我正在为TestStruct分配内存,但当我将ref传递给foo时,pointee指向 nil 。如果我使TestStruct (UnsafeMutablePointer<TestStruct>) 成为非可选项 - 一切都会很好 - bar打印 hello:123更新: 感谢@MartinR和@Hamish!工作代码:
struct TestStruct {
    var a = 0
}

func foo(ptr: UnsafeMutablePointer<TestStruct?>?) {
    ptr?.pointee?.a = 123
}

func bar(ptr: TestStruct?) {
    print("hello: \(ptr?.a)")
}

var ref = UnsafeMutablePointer<TestStruct?>.allocate(capacity: 1)

ref.initialize(to: TestStruct())

foo(ptr: ref)
bar(ptr: ref.pointee)


ref.deinitialize()
ref.deallocate(capacity: 1)

1
我已经运行了你的代码,并得到输出 hello: Optional(123) - Martin R
@MartinR Swift 3.0.2 和 OS X 10.12.3 - 0xAT
@Alexey 不要在游乐场测试它,它们非常容易出错和不可靠 - 总是在实际项目中测试代码。虽然话说回来,我也不指望你的代码能以可靠的方式运行。你从未初始化 refpointee,因此它可能会保存一些垃圾值,所以当你说 pointee?.a = ... 时就无法知道会发生什么。你需要先将 pointee 初始化为某个值。 - Hamish
@MartinR 我重新启动了Playground项目并得到了 hello: Optional(123),但是当我在 bar(ptr: ref.pointee) 之后添加了 print("\(ref.pointee?.a)"),我又一次收到了一个nil... 这是正常的Playground行为吗? - 0xAT
@Alexey:正如 Hamish 所说(当我正在写答案时),你的程序行为是未定义的。它可能工作,也可能不工作。你必须初始化内存。 - Martin R
显示剩余2条评论
1个回答

2
你的程序行为未定义。 allocate() 返回未初始化的内存:
/// Allocates and points at uninitialized aligned memory for `count`
/// instances of `Pointee`.
///
/// - Postcondition: The pointee is allocated, but not initialized.
public static func allocate(capacity count: Int) -> UnsafeMutablePointer<Pointee>

在使用之前必须进行初始化(并在释放内存之前进行去初始化):

let ref = UnsafeMutablePointer<TestStruct?>.allocate(capacity: 1)
ref.initialize(to: TestStruct())

foo(ptr: ref)
bar(ptr: ref.pointee)

ref.deinitialize()
ref.deallocate(capacity: 1)

以下是一个例子,不初始化内存会导致崩溃:

class TestClass {
    init() { print("init") }
    deinit { print("deinit") }
}

let ptr = UnsafeMutablePointer<TestClass>.allocate(capacity: 1)
ptr.pointee = TestClass()

赋值语句期望ptr.pointee处于已初始化状态并指向一个TestClass实例。由于ARC(自动引用计数),在分配新值时,之前指向的对象将被释放。如果ptr.pointee未初始化,则会崩溃。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接