2

DynamicArray現在、Swift で独自のデータ型を実装しようとしています。そのために、ポインターを少し使用しています。私のように、私はジェネリック型のrootを使用しています:UnsafeMutablePointerT

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:)などの数値型で初期化子を使用すると、完全に正常に機能します。次に、を使用するか、クラッシュしますが。ただし、一貫してクラッシュするわけではありませんが、ここで見られるように、数回コンパイルすることで実際に機能することがあります。IntDoubleFloatCharacterString

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
}

here でinitializeFrom(source:)説明されている方法を使用しています。それに準拠しているため、正常に動作するはずです。 私は今、このエラーが発生しています:collectionCollectionType

<stdin>:144:29: error: missing argument for parameter 'count' in call
    root.initializeFrom(collection)
                        ^

これも誤解を招くエラー メッセージですか?

4

1 に答える 1

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コンテンツとポイント先のメモリが必要になるため です。そうしないとリークします。構造体に a を含めることはできず、クラスにのみ含めることができないため、これを自動的に行うことはできません (これは、配列のユーザーが範囲外になる前に手動でこれを行うことを期待していないことを前提としています)。deallocDynamicArraydeinit

さらに、コピー オン ライトを介して値セマンティクス (Arrayおよび と同様) を実装する場合は、内部バッファーが複数回参照されているかどうかを検出する方法も必要になります。Stringを見ManagedBufferPointerて、これを処理するクラスを確認してください。

于 2015-02-27T17:42:22.210 に答える