【问题标题】:Inconsistencies when using UnsafeMutablePointer with String or Character types将 UnsafeMutablePointer 与 String 或 Character 类型一起使用时的不一致
【发布时间】:2015-02-27 14:34:25
【问题描述】:

我目前正在尝试在 Swift 中实现我自己的 DynamicArray 数据类型。为此,我使用了一些指针。作为我的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 分配了多少内存。因此,可以使用init(capacity:) 初始化程序创建DynamicArray 的实例,该初始化程序分配适当的内存量,并设置capacity 属性。
但后来我还实现了init(count:repeatedValue:) 初始化程序,它首先使用init(capacity: count) 分配所需的内存。然后它将该部分内存中的每个段设置为repeatedValue

init(count:repeatedValue:) 初始化器与IntDoubleFloat 等数字类型一起使用时,它可以正常工作。然后使用CharacterString,尽管它会崩溃。虽然它不会一直崩溃,但实际上有时会起作用,正如 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

为什么会这样?是否与 StringCharacter 持有不同长度的值有关?


更新 #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)
                        ^

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

【问题讨论】:

  • 我认为这是一个@MartinR 问题
  • 您不应该通过编辑之前的问题来提出新的不同问题……但是,我相信您在 1.1 中遇到了快速类型推断错误,该错误已在 1.2 测试版中修复。
  • 好的,以后我会尽量避免这种情况。 - 该死的

标签: string swift pointers generics unsafe-pointers


【解决方案1】:

是的,这可能不会与整数等基本惰性类型崩溃,但与字符串或数组有关,因为它们更复杂,并在创建/销毁时为自己分配内存。

它崩溃的原因是 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 结构之前的某个时间点,您需要 destroy 的内容和指向的内存 dealloc,否则会泄漏。由于您不能在结构中拥有deinit,只有一个类,因此无法自动执行此操作(这是假设您不希望数组的用户在它退出之前自己手动执行此操作范围)。

此外,如果您想通过写时复制来实现值语义(如ArrayString),您还需要一种方法来检测您的内部缓冲区是否被多次引用。看看ManagedBufferPointer,看看一个为你处理这个的类。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-03-18
    • 2021-01-26
    • 2018-02-06
    • 2016-03-22
    • 2015-09-15
    • 2010-09-22
    • 1970-01-01
    • 2015-09-12
    相关资源
    最近更新 更多