UnsafeRawPointer assumeMemoryBound vs. bindMemory

问题描述 投票:8回答:1

任何人都可以解释UnsafeRawPointer.assumimgMemoryBound(to:)UnsafeRawPointer.bindMemory(to:capacity:)之间有什么区别?

编译或运行时差的一个实际例子将更受欢迎。

Swift Doc说关于bindMemory(to:capacity:)

此API允许内存区域在程序中的不同点保存不相关的类型。将未初始化的内存绑定到类型会使内存准备存储该类型的值。已初始化的绑定内存将内存中的值重新解释为新类型。如果旧值非常重要(需要销毁)或者在被覆盖之前从内存中读取它们,则新类型必须与旧类型相互布局兼容。

是什么意思将未初始化的内存绑定到类型会使内存准备存储该类型的值?它分配了字节,对吧?那么在bindMemory(to:capacity:)完成后有什么不同?

swift pointers memory
1个回答
9
投票

Swift中分配的内存可以是:

  • 未初始化的原始内存
  • 未初始化的内存绑定到某个类型
  • 初始化内存绑定到一个类型

使用UnsafeMutableRawPointer.allocate(bytes:alignedTo:)分配内存时,会获得未初始化的原始内存。

使用UnsafeMutablePointer<T>.allocate(capacity:)分配内存时,会获得与T类型绑定的未初始化内存。

  • bindMemory(to:capacity:)(重新)将指针的内存绑定到一个新类型,并返回一个类型指针来访问它。它可以在任何上述状态的指向内存的指针上调用;虽然如果内存初始化,新绑定类型必须与旧绑定类型布局兼容,并且两种类型都应该是trivial。 请注意,此方法不执行分配或初始化;它只是改变了内存的绑定类型。
  • assumingMemoryBound(to:)是一种从原始指针获取类型指针的方法,该指针已经知道指向绑定到给定类型的内存。如果内存未绑定到此类型,则通过您返回的类型指针访问内存是未定义的行为。

这里需要注意的一件重要事情是,内存只能在给定时间绑定到一种类型。您可以自由重新绑定到其他类型(具有上述初始化内存的限制);但是,尝试访问绑定到给定类型的内存作为无关类型会违反严格别名,因此是未定义的行为。

另一件需要注意的是,相关类型和布局兼容类型是独立的概念:

  • T类型与U类型的布局兼容,如果绑定到类型U的内存可以按位重新解释为具有类型T。请注意,这不一定是双向关系。例如,如果Int的一个'实例'可以被重新解释为2 x (Int, Int),则(Int, Int)Int的布局兼容。反过来不可能是真的;你不能从单个(Int, Int)形成Int值。
  • 如果您可以将重叠内存与这些类型别名,则两种类型相关。例如,如果你有UnsafePointer<T>UnsafePointer<U>,如果TU是不相关的类型,那么它们就不能指向彼此重叠的内存。

但是,我不相信Swift已经正式定义了这些术语的任何规则(我希望这将具有ABI稳定性)。

那么在bindMemory(to:capacity:)完成后有什么不同?

目前,没什么。正如Andrew Trick says在邮件列表讨论中Martin linked to

绑定内存与编译器通信,内存位置对于类型化访问是安全的。在运行时没有任何事情发生 - 直到有人写了类型安全消毒剂。它影响内存位置的抽象状态,与用于访问该内存的指针变量无关。绑定内存返回一个类型指针,以方便和清晰,但没有什么特别的指针值。

有关此主题的进一步阅读,请参阅memory model explanation section of SE-0107以及此unofficial guide to strict aliasing in Swift

© www.soinside.com 2019 - 2024. All rights reserved.