- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
在我创建的结构中(在Xcode 10.1,Swift 4.2上)观察到的属性上使用UnsafeMutablePointer时,出现了一些意外的行为。请参阅以下游乐场代码:
struct NormalThing {
var anInt = 0
}
struct IntObservingThing {
var anInt: Int = 0 {
didSet {
print("I was just set to \(anInt)")
}
}
}
var normalThing = NormalThing(anInt: 0)
var ptr = UnsafeMutablePointer(&normalThing.anInt)
ptr.pointee = 20
print(normalThing.anInt) // "20\n"
var intObservingThing = IntObservingThing(anInt: 0)
var otherPtr = UnsafeMutablePointer(&intObservingThing.anInt)
// "I was just set to 0."
otherPtr.pointee = 20
print(intObservingThing.anInt) // "0\n"
最佳答案
每当您看到类似UnsafeMutablePointer(&intObservingThing.anInt)
的结构时,都应该非常警惕它是否会表现出不确定的行为。在绝大多数情况下,它会。
首先,让我们详细分析一下这里发生的事情。 UnsafeMutablePointer
没有任何采用inout
参数的初始化程序,那么此调用程序是什么?好的,编译器有一个特殊的转换,允许将&
前缀的参数转换为指向表达式引用的“存储”的可变指针。这称为inout到指针的转换。
例如:
func foo(_ ptr: UnsafeMutablePointer<Int>) {
ptr.pointee += 1
}
var i = 0
foo(&i)
print(i) // 1
&i
变成指向
i
的存储的可变指针。好的,但是当
i
没有任何存储空间时会发生什么?例如,如果计算得出该怎么办?
func foo(_ ptr: UnsafeMutablePointer<Int>) {
ptr.pointee += 1
}
var i: Int {
get { return 0 }
set { print("newValue = \(newValue)") }
}
foo(&i)
// prints: newValue = 1
i
的getter,并将结果值放入一个临时变量中。 foo
的调用。 i
的setter。 var j = i // calling `i`'s getter
foo(&j)
i = j // calling `i`'s setter
foo
的指针的生存期施加了重要的限制-它只能用于在调用
i
的过程中使
foo
的值发生变化。尝试转义指针并在调用
foo
之后使用它会导致仅修改临时变量的值,而不是
i
。
func foo(_ ptr: UnsafeMutablePointer<Int>) -> UnsafeMutablePointer<Int> {
return ptr
}
var i: Int {
get { return 0 }
set { print("newValue = \(newValue)") }
}
let ptr = foo(&i)
// prints: newValue = 0
ptr.pointee += 1
ptr.pointee += 1
是在使用临时变量的新值调用
i
的setter之后发生的,因此无效。
foo
的调用结束后,临时变量将保持有效。例如,优化程序可以在调用后立即将其取消初始化。
func bar() {
var i = 0
let ptr = foo(&i)
// Optimiser could de-initialise `i` here.
// ... making this undefined behaviour!
ptr.pointee += 1
}
var i: Int = 0 {
willSet(newValue) {
print("willSet to \(newValue), oldValue was \(i)")
}
didSet(oldValue) {
print("didSet to \(i), oldValue was \(oldValue)")
}
}
var _i: Int = 0
func willSetI(newValue: Int) {
print("willSet to \(newValue), oldValue was \(i)")
}
func didSetI(oldValue: Int) {
print("didSet to \(i), oldValue was \(oldValue)")
}
var i: Int {
get {
return _i
}
set {
willSetI(newValue: newValue)
let oldValue = _i
_i = newValue
didSetI(oldValue: oldValue)
}
}
foo
的示例与您调用
UnsafeMutablePointer
初始化程序的示例有什么关系?好吧,
UnsafeMutablePointer
has an initialiser that takes an UnsafeMutablePointer
argument(作为符合大多数标准库指针类型所遵循的强调的
_Pointer
协议(protocol)的结果)。
foo
函数相同–它接受
UnsafeMutablePointer
参数并返回它。因此,当您执行
UnsafeMutablePointer(&intObservingThing.anInt)
时,就转义了从inout到指针的转换产生的指针-正如我们已经讨论的那样,仅当它用于没有观察者的存储的全局或静态变量时才有效。
var intObservingThing = IntObservingThing(anInt: 0)
var otherPtr = UnsafeMutablePointer(&intObservingThing.anInt)
// "I was just set to 0."
otherPtr.pointee = 20
UnsafeMutablePointer
的初始化程序的调用期间有效。之后尝试使用它会导致不确定的行为。作为
matt demonstrates,如果要对
intObservingThing.anInt
进行范围内的指针访问,则要使用
withUnsafeMutablePointer(to:)
。
var normalThing = NormalThing(anInt: 0)
var ptr = UnsafeMutablePointer(&normalThing.anInt)
ptr.pointee = 20
normalThing
)是
struct
的易碎存储全局变量而没有观察者,因此在将来的发行版中,编译器很可能会保证为这种行为定义良好的行为。 ,而
anInt
是没有观察者的易碎存储属性。
关于swift - UnsafeMutablePointer.pointee和didSet属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53892190/
我正在围绕 GObject 构建包装器,并且我正在尝试为其创建通用指针 class Object { internal(set) var object = UnsafeMutablePoint
**更新。对那些回答不再有意义的人表示抱歉。 所以我想通了,无论我在 Data_pair_node 之后的行上放什么,在它执行之后,就是重置的时候!什么? : int insert(Table *t,
let data = Data() data.withUnsafeBytes { (uPtr: UnsafePointer) in var ptr = uPtr
我有下面的代码,并用智能指针包装了 Temple 对象。我明白了这个概念,但我不明白的是何时调用持有对象的析构函数。 想不到,我还没有实现~mySmartPointer,调用了模板析构函数。 输出 T
我正在尝试从使用 Unmanaged.passUnretained().toOpaque() 获得的 UnsafeMutableRawPointer 获取 UnsafeMutablePointer:
我一直致力于掌握 AUAudioUnits 背后的理念,并在 presentation video 中给出的 Xcode 中写下示例代码来自介绍该主题的 Apple 的 WWDC 2016。事实证明,
我是一名优秀的程序员,十分优秀!