【问题标题】:Warning: Initialization of 'UnsafeBufferPointer<T>' results in a dangling buffer pointer警告:“UnsafeBufferPointer<T>”的初始化会导致缓冲区指针悬空
【发布时间】:2020-07-06 12:36:24
【问题描述】:

更新到 Swift 5.2 / Xcode 11.4 后收到以下代码的警告:

extension Data {

    init<T>(from value: T) {
        var value = value
        let pointer = UnsafeBufferPointer(start: &value, count: 1)
        self.init(buffer: pointer)
    }

    func to<T>(type: T.Type) -> T {
        return self.withUnsafeBytes { $0.load(as: T.self) }
    }
}

上线 let pointer = UnsafeBufferPointer(start: &value, count: 1) 我得到了

“UnsafeBufferPointer”的初始化导致缓冲区指针悬空

我可以使用@silenceWarning,但它是肮脏的解决方案。也许我需要将指针存储在某个地方并在将来清理它?

【问题讨论】:

标签: swift unsafe-pointers swift5.2 xcode11.4


【解决方案1】:

我也遇到了这些烦人的警告。

var str = "aaaaabbbbbccccc"
var num1 = 1
var num2 = 22

var data = Data()
// Initialization of 'UnsafeBufferPointer<String>' results in a dangling buffer pointer
data.append(UnsafeBufferPointer(start: &str, count: 1)) 
// Initialization of 'UnsafeBufferPointer<Int>' results in a dangling buffer pointer
data.append(UnsafeBufferPointer(start: &num1, count: 1))
// Initialization of 'UnsafeBufferPointer<Int>' results in a dangling buffer pointer 
data.append(UnsafeBufferPointer(start: &num2, count: 1)) 

考虑到@greg 的回答,我将Data.append 放入withUnsafePointer 的闭包中,它不再显示警告。

withUnsafePointer(to: &str) { data.append(UnsafeBufferPointer(start: $0, count: 1)) } // ok
withUnsafePointer(to: &num1) { data.append(UnsafeBufferPointer(start: $0, count: 1)) } // ok
withUnsafePointer(to: &num2) { data.append(UnsafeBufferPointer(start: $0, count: 1)) } // ok

这是扩展名

extension Data {
    init<T>(value: T) {
        self = withUnsafePointer(to: value) { (ptr: UnsafePointer<T>) -> Data in
            return Data(buffer: UnsafeBufferPointer(start: ptr, count: 1))
        }
    }

    mutating func append<T>(value: T) {
        withUnsafePointer(to: value) { (ptr: UnsafePointer<T>) in
            append(UnsafeBufferPointer(start: ptr, count: 1))
        }
    }
}

【讨论】:

  • append(.init(value: value))
【解决方案2】:

我的代码看起来几乎与您正在执行的操作完全相同,并且收到了相同的警告。我的与讨论相关的方式略有不同

init<T>(from value: T) {
    var value = value
    self.init(buffer: UnsafeBufferPointer(start: &value, count: 1))
}

这仍然会生成 UnsafeBufferPointer 正在生成悬空指针的警告,但提示说“生成的指针仅在调用 'init(start:count:)' 期间有效”

但是 UnsafeBufferPointer 的返回值没有分配给任何东西,所以如果我尝试的话,我不能在初始化范围之外使用它。所以这里的编译器警告我不要做我无论如何都做不到的事情。

我猜 Data.init(buffer: ) 可能正在存储 ptr,但我会假设如果它接受 UnsafeBufferPointer,它就会承担正确使用它的责任

无论如何,这仍然不能真正解决您的问题。我用这个绕过了警告

init<T>(from value: T) {
    var value = value
    var myData = Data()
    withUnsafePointer(to:&value, { (ptr: UnsafePointer<T>) -> Void in
        myData = Data( buffer: UnsafeBufferPointer(start: ptr, count: 1))
    })
    self.init(myData)
}

这不会产生警告并且似乎可以工作(无论如何在我的应用程序中)。能不能通过这里的专家的考验是另一回事。

有点让我怀念 HLock 和 HUnlock 的日子

【讨论】:

    【解决方案3】:

    这从来都不是安全的,很高兴 Swift 团队已经清理了它:

    let pointer = UnsafeBufferPointer(start: &value, count: 1)
    

    在这行代码的末尾,pointer 立即无效。没有保证value 甚至存在于下一行代码中。我不确定你想在这里实现什么,但这从来都不是一种安全的方法。您可能正在寻找 .withUnsafeBytes 方法之一,这取决于您正在处理的内容。

    【讨论】:

    • 虽然你的答案可能是正确的,但如果你展示一个如何失败的例子会更好。有几个使用 Unsafe*Pointer 进行强制转换和转换的示例 (stackoverflow.com/a/27456220/5276890) 现在会生成此警告。
    【解决方案4】:

    我的操场是这样做的(根据 SO https://stackoverflow.com/a/38024025/5709159 上的这个答案)

    do {
      let array: [Float] = [1.2, 2.2]
      let data = withUnsafeBytes(of: array) { Data($0) }
      
      let restore: [Float] = data.withUnsafeBytes {
        $0.load(as: [Float].self)
      }
      
      array == restore //true
    }
    

    你可以使用你的类型而不是[Float]

    【讨论】:

      【解决方案5】:

      在这里找到了一个不错的答案round trip Swift number types to/from Data

      // value into Data
      let data = withUnsafeBytes(of: value) { Data($0) }
      // Data into value
      _ = withUnsafeMutableBytes(of: &value, { data.copyBytes(to: $0)} )
      

      【讨论】:

        猜你喜欢
        • 2020-10-14
        • 2020-07-06
        • 2020-10-18
        • 2020-08-02
        • 2020-07-30
        • 1970-01-01
        • 2017-11-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多