Swift & Objective-C

Swift Copy-on-Write:自作バッファで分離の時点を確かめる

参照型の保存領域を使う小さなバッファを実装し、共有中の最初の書き込みで一度だけ分離することと、単独所有時の挙動を検証します。

読了 3 分
Swift Copy-on-Write:自作バッファで分離の時点を確かめるのカバー画像

Copy-on-Writeは値の意味を保ちながら保存領域のコピーを遅らせる実装戦略です。共有中なら変更前に分離し、単独所有なら直接変更します。すべてのstructに自動で備わる機能ではありません。

仕組みと設計の判断基準

標準コレクションの値の意味と、自作保存領域の実装責任は別です。ここではprivateなクラスに整数配列を持たせ、変更メソッドでisKnownUniquelyReferencedにより強参照の一意性を調べます。すべての変更経路でこの規律を守る必要があります。 一次資料

再現コード

IntBufferの代入直後、同じStorageを参照することをidentityで確認します。コピー側へ3を追加すると保存領域が分離し、原本の配列は保たれるはずです。次に4を追加する時点ではStorageを単独所有しているので、追加の分離は不要です。

この独立したサンプルは2026-10-23に、arm64 macOS向けのApple Swift 6.4をSwift 6言語モードで実行しました。ネットワーク接続や追加パッケージは不要です。

Swiftファイル全体をダウンロード

ダウンロード先のフォルダーで実行してください。検証条件を満たさない場合はpreconditionで停止します。検証が削除されるため、-Ouncheckedは使用しないでください。

swift -swift-version 6 swift-copy-on-write-prototype-pattern.swift
struct IntBuffer {
    private final class Storage {
        var values: [Int]
        init(_ values: [Int]) { self.values = values }
    }
    private var storage: Storage
    private(set) var detachments = 0
    init(_ values: [Int]) { storage = Storage(values) }
    var values: [Int] { storage.values }
    func sharesStorage(with other: IntBuffer) -> Bool {
        storage === other.storage
    }
    mutating func append(_ value: Int) {
        if !isKnownUniquelyReferenced(&storage) {
            storage = Storage(storage.values)
            detachments += 1
        }
        storage.values.append(value)
    }
}

let original = IntBuffer([1, 2])
var copy = original
precondition(copy.sharesStorage(with: original))
copy.append(3)
precondition(!copy.sharesStorage(with: original))
precondition(original.values == [1, 2] && copy.values == [1, 2, 3])
copy.append(4)
precondition(copy.detachments == 1 && copy.values == [1, 2, 3, 4])
print("shared-before=true shared-after=false detachments=1 original=[1,2] copy=[1,2,3,4]")

実行結果と読み取り方

shared-before=true shared-after=false detachments=1 original=[1,2] copy=[1,2,3,4]

detachments=1は、自作Storageラッパーの分離が一度だったことを示します。原本は[1,2]、コピーは[1,2,3,4]です。内部Arrayバッファの実際の割り当て回数ではありません。そのArrayは独自のCoW実装を利用できます。

適用範囲と注意点

単一実行フロー用の学習例であり、スレッド安全なコレクションではありません。一意性検査は同期機構ではありません。クラスを要素とする配列も要素を深く複製しないため、値型がすべてのプロトタイプパターンを不要にするとは言えません。

次に確認すること

独立コピーが必要なデータと共有可能なデータを分けてください。性能は実際の負荷で測定し、自作型が必要でなければ標準コレクションを優先します。内部参照の共有はclassとstructの実験で確認できます。

関連する実験

出典と確認基準