我目前正在尝试在Swift中实现自己的DynamicArray
数据类型。为此,我正在使用指针。正如我的root
我正在使用通用类型UnsafeMutablePointer
的{{1}}:
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
初始值设定项,它首先使用init(count:repeatedValue:)
分配所需的内存。然后,它将该部分内存中的每个段设置为init(capacity: count)
。
将repeatedValue
初始值设定项与init(count:repeatedValue:)
,Int
或Double
等数字类型一起使用时,效果非常好。然后使用Float
或Character
虽然崩溃了。它虽然没有一致地崩溃,但实际上有时会起作用,如here所示,通过编译几次。
String
为什么会这样?是否与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
持有不同长度的值有关?
现在@AirspeedVelocity用Character
解决了这个问题。 init(count:repeatedValue:)
包含另一个初始值设定项,它最初的工作方式与DynamicArray
类似。我把它改成了工作,正如@AirspeedVelocity描述的那样init(count:repeatedValue:)
:
init(count:repeatedValue:)
我正在使用here描述的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:)
符合collection
,因此它应该可以正常工作
我现在收到这个错误:
CollectionType
这只是一个误导性错误信息吗?
答案 0 :(得分:2)
是的,这可能不会像整数这样的基本惰性类型崩溃,但会与字符串或数组一起崩溃,因为它们更复杂并且在创建/销毁时为自己分配内存。
它崩溃的原因是UnsafeMutablePointer
内存需要在使用之前进行初始化(同样,在解除分配之前需要使用destroy
去除)。
因此,您应该使用memory
方法,而不是分配给initialize
属性:
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
}
但是,您需要注意的是,此代码目前不可避免地会泄漏内存。原因是,在destroy
结构被破坏之前,您需要dealloc
内容和DynamicArray
指向内存,否则您将泄漏。由于结构中不能有deinit
,只有一个类,这是不可能自动执行的(假设你不希望你的数组用户在它去之前自己手动完成超出范围)。
此外,如果您想通过写时复制实现值语义(与Array
和String
一样),您还需要一种检测内部缓冲区是否被引用的方法多次。请查看ManagedBufferPointer
以查看为您处理此问题的课程。