将UnsafeMutablePointer与String或Character类型一起使用时出现不一致

时间:2015-02-27 14:34:25

标签: string swift pointers generics unsafe-pointers

我目前正在尝试在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:)IntDouble等数字类型一起使用时,效果非常好。然后使用FloatCharacter虽然崩溃了。它虽然没有一致地崩溃,但实际上有时会起作用,如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持有不同长度的值有关?


更新#1:

现在@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

这只是一个误导性错误信息吗?

1 个答案:

答案 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,只有一个类,这是不可能自动执行的(假设你不希望你的数组用户在它去之前自己手动完成超出范围)。

此外,如果您想通过写时复制实现值语义(与ArrayString一样),您还需要一种检测内部缓冲区是否被引用的方法多次。请查看ManagedBufferPointer以查看为您处理此问题的课程。