我目前正在尝试实现我自己的 DynamicArray
Swift 中的数据类型。为此,我稍微使用了指针。作为我的root
我正在使用 UnsafeMutablePointer
通用类型 T
:
struct DynamicArray<T> {
private var root: UnsafeMutablePointer<T> = nil
private var capacity = 0 {
didSet {
//...
}
}
//...
init(capacity: Int) {
root = UnsafeMutablePointer<T>.alloc(capacity)
self.capacity = capacity
}
init(count: Int, repeatedValue: T) {
self.init(capacity: count)
for index in 0..<count {
(root + index).memory = repeatedValue
}
self.count = count
}
//...
}
现在如您所见,我还实现了 capacity
属性告诉我当前为 root
分配了多少内存。 。因此,我们可以创建 DynamicArray
的一个实例。使用init(capacity:)
初始化程序,分配适当的内存量,并设置 capacity
属性(property)。
但后来我也实现了 init(count:repeatedValue:)
初始化程序,它首先使用 init(capacity: count)
分配所需的内存。然后,它将该部分内存中的每个段设置为 repeatedValue
.
使用 init(count:repeatedValue:)
时具有数字类型的初始值设定项,如 Int
, Double
,或Float
它工作得很好。然后使用 Character
,或String
虽然它崩溃了。虽然它不会持续崩溃,但有时确实有效,如 here 所示。 ,通过编译几次。
var a = DynamicArray<Character>(count: 5, repeatedValue: "A")
println(a.description) //prints [A, A, A, A, A]
//crashes most of the time
var b = DynamicArray<Int>(count: 5, repeatedValue: 1)
println(a.description) //prints [1, 1, 1, 1, 1]
//works consistently
为什么会发生这种情况?和String
有关系吗?和Character
保存不同长度的值?
更新#1:
现在@AirspeedVelocity用init(count:repeatedValue:)
解决了这个问题。 DynamicArray
但包含另一个初始化程序,它最初的工作方式与 init(count:repeatedValue:)
类似。 。我将其更改为工作,如 @AirspeedVelocity 所描述的 init(count:repeatedValue:)
不过:
init<C: CollectionType where C.Generator.Element == T, C.Index.Distance == Int>(collection: C) {
let collectionCount = countElements(collection)
self.init(capacity: collectionCount)
root.initializeFrom(collection)
count = collectionCount
}
我正在使用initializeFrom(source:)
方法如所述here 。自从 collection
符合CollectionType
它应该工作正常。
我现在收到此错误:
<stdin>:144:29: error: missing argument for parameter 'count' in call
root.initializeFrom(collection)
^
这又是一个误导性的错误消息吗?
最佳答案
是的,这对于整数等基本惰性类型可能不会崩溃,但对于字符串或数组会崩溃,因为它们更复杂并且在创建/销毁时为自己分配内存。
崩溃的原因是 UnsafeMutablePointer
内存在使用之前需要初始化(同样,在释放之前需要使用 destroy
取消初始化)。
因此,您应该使用 initialize
方法,而不是分配给 memory
属性:
for index in 0..<count {
(root + index).initialize(repeatedValue)
}
由于从另一个值集合进行初始化非常常见,因此还有另一个版本的 initialize
接受一个值。您可以将其与另一个辅助结构 Repeat
结合使用,它是重复多次的相同值的集合:
init(count: Int, repeatedValue: T) {
self.init(capacity: count)
root.initializeFrom(Repeat(count: count, repeatedValue: repeatedValue))
self.count = count
}
但是,您还需要注意的是,此代码目前不可避免地会泄漏内存。原因是,在销毁 DynamicArray
结构之前,您需要在某个时刻销毁
内容并dealloc
指向的内存,否则你会泄漏。由于在结构中不能有 deinit,而只能在类中,所以这不可能自动完成(假设您不希望数组的用户自己手动执行此操作)在它超出范围之前)。
此外,如果您想通过写时复制来实现值语义(如 Array
和 String
),您还需要一种方法来检测是否您的内部缓冲区被多次引用。查看 ManagedBufferPointer
以查看为您处理此问题的类。
关于string - 将 UnsafeMutablePointer 与 String 或 Character 类型一起使用时出现不一致,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28767513/