33

更新到 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,但它是肮脏的解决方案。也许我需要将指针存储在某个地方并在将来清理它?

4

6 回答 6

17

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

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.appendintowithUnsafePointer关闭,它不再显示警告。

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))
        }
    }
}
于 2020-04-08T08:00:59.547 回答
11

我的代码看起来几乎与您所做的完全一样,并且收到了相同的警告。我的在与讨论相关的方式上略有不同

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

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

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

我猜 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 的日子

于 2020-03-31T16:26:35.000 回答
6

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

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

这行代码的末尾,pointer立即无效。value甚至在下一行代码中也不存在承诺。我不确定你想在这里实现什么,但这从来都不是一种安全的方法。您可能正在寻找的是其中一种.withUnsafeBytes方法,这取决于您正在从事的工作。

于 2020-03-25T21:43:25.993 回答
0

我的操场是这样做的(根据 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]你可以使用你的类型

于 2021-07-12T08:09:59.263 回答
0

这是一个正确的解决方案:


extension Data {

    init<T>(from value: T) {
        // 1
        let pointer = UnsafeMutablePointer<T>.allocate(capacity: 1)
        // 2
        pointer.initialize(to: value)
        defer {
            pointer.deinitialize(count: 1)
            pointer.deallocate()
        }
        // 3
        let bufferPointer = UnsafeBufferPointer(start: pointer, count: 1)
        self.init(buffer: bufferPointer)
    }

    func to<T>(type: T.Type) -> T {
        return self.withUnsafeBytes { $0.load(as: T.self) }
    }
}
  1. 您使用 UnsafeMutablePointer.allocate 分配内存。泛型参数让 Swift 知道您正在使用指针来加载和存储值
  2. 您必须在使用前初始化类型化内存并在使用后取消初始化。您可以分别使用 initialize 和 deinitialize 方法来执行此操作。
  3. 您将指针转换为 UnsafeBufferPointer。它指向安全内存,直到初始化程序结束。
于 2022-02-26T16:14:07.857 回答
-1

在这里找到了一个很好的答案往返数据类型的往返 Swift 数字类型

// value into Data
let data = withUnsafeBytes(of: value) { Data($0) }
// Data into value
_ = withUnsafeMutableBytes(of: &value, { data.copyBytes(to: $0)} )
于 2020-05-15T00:41:06.010 回答