Swift 缓冲区指针和数组索引
Swift buffer pointer & array indexing
我有以下代码:
public struct HistogramData {
var red:[vImagePixelCount] = []
var green:[vImagePixelCount] = []
var blue: [vImagePixelCount] = []
var alpha: [vImagePixelCount] = []
}
然后我按如下方式访问它:
var data: HistogramData
...
let red:UnsafeMutablePointer<vImagePixelCount> = UnsafeMutablePointer(mutating: data.red)
let green:UnsafeMutablePointer<vImagePixelCount> = UnsafeMutablePointer(mutating: data.green)
let blue:UnsafeMutablePointer<vImagePixelCount> = UnsafeMutablePointer(mutating: data.blue)
以上行不正确,XCode 显示了悬空指针警告。所以我将代码修改为:
data.red.withUnsafeMutableBufferPointer { redPtr in
data.green.withUnsafeMutableBufferPointer { greenPtr in
data.blue.withUnsafeMutableBufferPointer { bluePtr in
let red = redPtr.baseAddress!
let green = greenPtr.baseAddress!
let blue = bluePtr.baseAddress!
for i in 0..<256 {
if red[i] > maxR {
maxR = red[i]
}
if green[i] > maxG {
maxG = green[i]
}
if blue[i] > maxB {
maxB = blue[i]
}
}
...
}
尽管上面的代码有效,但我不确定我们是否可以在 Swift 中的 baseAddress 上使用数组索引。正确的方法可能是将内存绑定到一定的大小,但是当数组的大小没有指定时,bindMemory 是如何工作的呢?上面的代码如果错了怎么改(虽然能用,但不一定对)?
您的代码是正确的。
someArray.withUnsafeMutableBufferPointer { bufPtr in ... }
使用引用数组(可变)元素存储的 UnsafeMutableBufferPointer
调用闭包,并且已经绑定到元素的类型。仅当您想以 不同 类型访问内存时才需要重新绑定。
然后bufPtr[i]
和bufPtr.baseAddress![i]
都访问i-th数组元素(通过UnsafeMutableBufferPointer
和UnsafeMutablePointer
的subscript
方法) .唯一的区别是前者在调试模式下对索引进行了边界检查。
在优化的代码中,两种下标方法都可以在不进行边界检查的情况下访问元素存储。 可以成为一种提高性能的方法(以安全为代价)。
如果您的这部分代码对性能至关重要,并且不安全访问是否真的比“正常”数组访问更快,我建议进行基准测试。
我有以下代码:
public struct HistogramData {
var red:[vImagePixelCount] = []
var green:[vImagePixelCount] = []
var blue: [vImagePixelCount] = []
var alpha: [vImagePixelCount] = []
}
然后我按如下方式访问它:
var data: HistogramData
...
let red:UnsafeMutablePointer<vImagePixelCount> = UnsafeMutablePointer(mutating: data.red)
let green:UnsafeMutablePointer<vImagePixelCount> = UnsafeMutablePointer(mutating: data.green)
let blue:UnsafeMutablePointer<vImagePixelCount> = UnsafeMutablePointer(mutating: data.blue)
以上行不正确,XCode 显示了悬空指针警告。所以我将代码修改为:
data.red.withUnsafeMutableBufferPointer { redPtr in
data.green.withUnsafeMutableBufferPointer { greenPtr in
data.blue.withUnsafeMutableBufferPointer { bluePtr in
let red = redPtr.baseAddress!
let green = greenPtr.baseAddress!
let blue = bluePtr.baseAddress!
for i in 0..<256 {
if red[i] > maxR {
maxR = red[i]
}
if green[i] > maxG {
maxG = green[i]
}
if blue[i] > maxB {
maxB = blue[i]
}
}
...
}
尽管上面的代码有效,但我不确定我们是否可以在 Swift 中的 baseAddress 上使用数组索引。正确的方法可能是将内存绑定到一定的大小,但是当数组的大小没有指定时,bindMemory 是如何工作的呢?上面的代码如果错了怎么改(虽然能用,但不一定对)?
您的代码是正确的。
someArray.withUnsafeMutableBufferPointer { bufPtr in ... }
使用引用数组(可变)元素存储的 UnsafeMutableBufferPointer
调用闭包,并且已经绑定到元素的类型。仅当您想以 不同 类型访问内存时才需要重新绑定。
然后bufPtr[i]
和bufPtr.baseAddress![i]
都访问i-th数组元素(通过UnsafeMutableBufferPointer
和UnsafeMutablePointer
的subscript
方法) .唯一的区别是前者在调试模式下对索引进行了边界检查。
在优化的代码中,两种下标方法都可以在不进行边界检查的情况下访问元素存储。 可以成为一种提高性能的方法(以安全为代价)。
如果您的这部分代码对性能至关重要,并且不安全访问是否真的比“正常”数组访问更快,我建议进行基准测试。