素晴らしいSwiftのポインタ型の解説

# 導入

Swiftにはポインタを表すための型として `UnsafePointer<T>` とその仲間達があります。CoreFoundationなどC言語のライブラリを使う時などに利用することになります。これらのポインタ型のAPIはとてもよく考えられた素晴らしいものです。この記事ではそれを紹介、解説します。C言語ユーザ、C++ユーザにとっても興味深い内容だと思います。(swift 3.0.2)

# ポインタ型

ポインタ型には下記のものがあります。

基本ポインタ型

- `UnsafePointer<T>`
- `UnsafeMutablePointer<T>`
- `UnsafeRawPointer`
- `UnsafeMutableRawPointer`
- `UnsafeBufferPointer<T>`
- `UnsafeMutableBufferPointer<T>`
- `UnsafeRawBufferPointer`
- `UnsafeMutableRawBufferPointer`

言語ブリッジ用

- `OpaquePointer`
- `CVaListPointer`
- `AutoreleasingUnsafeMutablePointer<T>`

やたら多いですね。

# 基本ポインタ型の属性

最も基本的なポインタ型は `UnsafePointer<T>` です。T型の値へのポインタを表します。参照先のTの値はイミュータブルになります。 `UnsafePointer<T>` 自体はstructなので、`let`と`var`によってポインタ自体の不変性を表すことができます。

```swift
func f(_ x: UnsafePointer<Int>) {
	let a: UnsafePointer<Int> = x
	var b: UnsafePointer<Int> = x
}
```

上記をC言語で表すと下記のようになります。

```c
void f(const int * const x) {
	const int * const a = x;
	const int * b = x;
}
```

`UnsafePointer<T>` に対して、3つの属性が付くことで別の型になります。組み合わせは2x2x2の8通りあります。

## Mutability

参照先Tの値が変更可能なミュータブル版があります。名前にはMutableが付きます。イミュータブル版からは `mutating` ラベル付きのコンストラクタで変換することができます。逆にミュータブル版からイミュータブル版へは、ラベル無しコンストラクタで変換できます。

```swift
public struct UnsafePointer<Pointee> : Strideable, Hashable {
	...
    public init(_ other: UnsafeMutablePointer<Pointee>)
    ...
}

public struct UnsafeMutablePointer<Pointee> : Strideable, Hashable {
	...
    public init(mutating other: UnsafePointer<Pointee>)
    ...
}
```

## 型付きと型無し

`UnsafePointer<T>` は参照先の型Tを型パラメータとして持っていましたが、この型情報を持たない版があります。型情報を持たない版の名前には `Raw` が付きます。例えばC言語での `const void *` がSwiftからはこの `UnsafeRawPointer` として見えます。ポインタの参照先の型が不明な時に使います。 

元々導入の経緯としては、 `UnsafePointer<T>` だけではある種のコードでstrict aliasingに関するバグが生じる可能性があり、それを回避するためのmemcpyセマンティクスを持った `UnsafeRawPointer` が必要となったそうです。

詳しいことは規格提案時の文書に書いてあります。[UnsafeRawPointer API](https://github.com/apple/swift-evolution/blob/master/proposals/0107-unsaferawpointer.md)

また、strict aliasingについては下記がわかりやすいです。[（翻訳）C/C++のStrict Aliasingを理解する または - どうして#$@##@^%コンパイラは僕がしたい事をさせてくれないの！](http://d.hatena.ne.jp/yohhoy/20120220/p1)

型付きと型無しの間の変換については後述します。

## ポインタとバッファ

C言語では配列を表すためにポインタをよく使いますが、いわゆる配列的に扱うためにはポインタに加えて要素数を一緒に知っておく必要があります。そこでこのポインタと要素数をセットにして表した配列を表すのが `UnsafeBufferPointer<T>` です。イミュータブルとミュータブル、型付きと型無しに対応して、4種類の `Buffer` があります。

`UnsafeBufferPointer<T>` はコンストラクタで開始アドレスと要素数を受け取るようになっています。そして `Collection` プロトコルを継承しています。

```swift
public struct UnsafeBufferPointer<Element> : Indexable, Collection, RandomAccessCollection {
	...
    public init(start: UnsafePointer<Element>?, count: Int)
    ...
    public var baseAddress: UnsafePointer<Element>? { get }
    ...
    public var count: Int { get }
    ...
}
```

# ブリッジ用の型

## OpaquePointer

`OpaquePointer` はC言語のopaque pointerと呼ばれるパターンの型を表すためのものです。opaque pointerというのは、型の名前だけ前方宣言されているが型の定義が見えていないために、参照先へのアクセスについて実質なんの情報も無いポインタの事です。ライブラリ外部に対して、ライブラリ内部の詳細を隠蔽するために利用されたりします。Swiftでは型の名前だけ見えるが定義は見えない、という事は起こりませんが、C言語上で定義されたopaque pointerをSwiftから読み込んだ時にはそれを表現する必要があるため、この型が使われます。

例えば下記のCソースがあったとします。

```c
struct CatImpl;
struct Cat {
	CatImpl * impl;
}
void PassCat(const Cat * a);
void PassCatImpl(const CatImpl * b);
```

Swiftからは2つの関数は下記のように見えます。

```swift
func PassCat(a: UnsafePointer<Cat>?)
func PassCatImpl(b: OpaquePointer?)
```

`UnsafePointer<T>` と相互にコンストラクタを通じて変換ができます。

```swift
public struct UnsafePointer<Pointee> : Strideable, Hashable {
	...
    public init(_ from: OpaquePointer)
    ...
}

public struct OpaquePointer : Hashable {
	...
    public init<T>(_ from: UnsafePointer<T>)
    ...
}
```

## CVaListPointer

C言語で可変長引数を扱う時には、 `...` という特殊表記や `va_list` という特殊な型を使いますが、 `va_list` を扱うためのポインタが `CVaListPointer` です。

## AutoreleasingUnsafeMutablePointer

調べられていません。Objective-Cにおいて `__autoreleasing` 修飾子がついたポインタをSwiftから見るとこれになる気がしますがわかりません。

# Optionalとポインタとnullability

Swiftのポインタ型はNULLになりません。言い換えると、 `UnsafePointer<T>` は non-null なポインタです。nullableなポインタはOptionalを使って `UnsafePointer<T>?` として表します。 **Swiftではポインタの取扱においても、 `if let` 構文などの null安全機構が使えるのです。** 

`UnsafePointer<T>`、`UnsafeMutablePointer<T>`、`OpaquePointer` の間での変換コンストラクタについては、Optional版があり、引数としてnilが渡されるとコンストラクタもnilを返します。

```swift
public struct UnsafePointer<Pointee> : Strideable, Hashable {
	...
    public init?(_ from: OpaquePointer?)
    ...
    public init?(_ other: UnsafeMutablePointer<Pointee>?)
    ...
}
```

`UnsafeBufferPointer<T>` はそのままの型で nullableポインタです。コンストラクタで受けるポインタが最初からOptionalで受けていて、そこにnilを渡すと、 `baseAddress` プロパティがnilになります。

# 基本的なアクセス

`UnsafePointer<T>` の参照先は `pointee` プロパティでアクセスできます。C言語では デリファレンス演算子(`*`)や アロー演算子(`->`) で書いていたやつです。また、subscriptアクセスができるので、連続確保したメモリ領域を配列のようにアクセスできます。

```swift
public struct UnsafePointer<Pointee> : Strideable, Hashable {
	...
    public var pointee: Pointee { get }
    ...
    public subscript(i: Int) -> Pointee { get }
    ...
}
```

ミュータブル版だとこれが書き込み可能になります。

```swift
public struct UnsafeMutablePointer<Pointee> : Strideable, Hashable {
	...
    public var pointee: Pointee { get nonmutating set }
	...
    public subscript(i: Int) -> Pointee { get nonmutating set }
	...
}
```

型無しのRaw版にはこれらのプロパティはありません。型を割り当てないと参照先にはアクセスできないようになっています。

# ポインタの3つの状態

`UnsafePointer<T>` が指し示すメモリには状態が3つあります。

- not allocated
- allocated but uninitialized
- initialized

この3つの状態の区別が、Swiftのポインタ型を支える重要な概念になります。これらの3つの状態は型システムによっては区別されません。プログラマが自分の今扱っているポインタがどの状態であるかを正確に理解している必要があります。

しかしこれはSwiftによって追加された仕様などではなく、本質的にポインタというものにたいして存在する概念です。これを以下に説明します。

## メモリ確保

アロケートされている状態というのは、ポインタの指し示すメモリ領域が確保されているという事です。逆にアロケートされていない状態というのは、ポインタがNULLであるか、指し示すメモリ領域が解放されているという事です。

ここで `UnsafePointer<T>` が扱うメモリ領域の大きさは、必ずしも値1つ分のサイズとは限りません。複数要素格納できるように直列に確保されたメモリ領域も取り扱えます。

メモリ確保はミュータブル版のポインタのstaticメソッド、 `allocate` によって行えます。

```swift
public struct UnsafeMutablePointer<Pointee> : Strideable, Hashable {
   	...
    public static func allocate(capacity count: Int) -> UnsafeMutablePointer<Pointee>
    ...
}
```

引数 `count` は連続何個分のメモリ領域を確保するかの個数です。このメソッドは値の型 `Pointee` に応じて、アライメント(alignment)とストライド(stride)が調整されます。アライメントというのは、その値が置かれるメモリアドレスの、アドレスの値に対する整数比の制約です。例えばアライメントが8の場合は、メモリアドレスは必ず8の倍数になります。 `MemoryLayout<T>.alignment` で取得できます。ストライドというのは、連続確保する時にそれぞれの値がアドレスを何バイトずつズレて配置されるかという値です。例えば、型のメモリサイズが5バイトであっても、ストライドが8バイトである場合、1つの要素のためには8バイトずつ割り当てられ、3バイトずつ空白が空きます。 `MemoryLayout<T>.stride` で取得できます。これらの値はコンパイラによって決められ、プログラマが任意に定める事ができません。

型無しの `UnsafeRawPointer` の場合、これらの値がわからないので、 `allocate` のパラメータが異なります。

```swift
public struct UnsafeMutableRawPointer : Strideable, Hashable {
    public static func allocate(bytes size: Int, alignedTo: Int) -> UnsafeMutableRawPointer
}
```

純粋なバイト数と、アライメント値を指定するようになっています。連続確保したい場合は、先述したストライドを考慮してサイズを計算する必要があります。

アロケートされたメモリ領域を表すポインタは non-null なので、どちらの返り値も 非Optional になっています。また、イミュータブルなメモリ領域を確保しても何も嬉しくないので、これらのstaticメソッドはミュータブル版の型に定義されています。

アロケートされたメモリを解放するには、 `deallocate` メソッドを呼び出します。

```swift
public struct UnsafeMutablePointer<Pointee> : Strideable, Hashable {
    public func deallocate(capacity: Int)
}
```

## メモリ初期化状態

Initializedというのは、そのメモリ領域に値が存在するかどうかを表す概念です。確保しただけのメモリ領域は本当にただのメモリ領域で、そこに値はまだ存在していない、未初期化な状態です。

初期化済みか未初期化であるかは、そのポインタの参照先にアクセスして値を **読み込む時** と **書き込む時** に問題になります。

未初期化なメモリ領域から値を読み込んでしまえば、メモリ上の状態はどんなメチャクチャなものかわからないので、とんでもない値が入っている可能性があり、クラッシュの危険があります。これはわかりやすいと思います。面白いのは、書き込みに関しての場合です。

一般にSwiftの `var` で定義する変数について考えてみます。下記のように、 `Cat` 型(参照型)とそれを保持する `CatHouse` 型(値型)があったとします。

```swift
class Cat {
}

struct CatHouse {
    var cat: Cat?
}
```

下記のような `App` 型が、 `CatHouse` 型のプロパティを持っていて、これを `update`　メソッドの中で書き換えたとします。

```swift
class App {
    init (a: CatHouse) {
        self.a = a
    }

    var a: CatHouse
    
    func update(b: CatHouse) {
        self.a = b
    }
}
```

この時swiftのARC機構によって `b` のCatHouseが持っている `cat` の参照カウンタを1増やす事になりますが、もう一つ忘れてはならないのが、 **もともと `a` に入っていた古いCatHouseが持っていた `cat` の参照カウンタを1減らす処理が生じる** 事です。つまり一般にswiftにおいて値のコピーが生じる時、コピーによって消される **古い値の破壊処理が発生します** 。

さて、ポインタの参照先に値を書き込むときの事を考えてみます。ポインタの参照先に値を書き込む時も、そこに変数があるのと同じことですから、元々あった値の破壊処理が必要になります。しかし、確保したばかりでまだ1度も値を書き込んでいない時はどうでしょうか。その状態で元々あった値の破壊処理をしたらまずいことになります。値が書き込まれていないでたらめなメモリ状態だからです。

そこで初期化・未初期化の区別が必要になります。 `UnsafePointer<T>` の `pointee` プロパティは、初期化済みのときにしか使ってはいけない規約になっています。未初期化のメモリ領域に書き込むためには `initialize` メソッド、 初期化済みのメモリ領域を未初期化に戻すためには `deinitialize` メソッドを使用します。


```swift
public struct UnsafeMutablePointer<Pointee> : Strideable, Hashable {
	...
    public func initialize(to newValue: Pointee, count: Int = default)
    ...
    public func deinitialize(count: Int = default) -> UnsafeMutableRawPointer
    ...
    public func move() -> Pointee
    ...
}
```

さて、メモリ領域は複数要素分を確保する事が可能でしたから、これらのメソッドには `count` 引数があります。 `initialize` については `to` 引数で指定した値で、 `count` 個の要素を埋めます。 この際、元々のメモリ領域に対する破壊処理は行わないわけです。 逆に `deinitialize` メソッドは値の破壊処理だけを行われます。 `move` メソッドは、要素数が1個の時の `deinitialize` で、値を返り値として返してくれます。 ちょうど C++の `std::move` と同じ名前で、ムーブセマンティクスが実現されている事がわかります。

実験してみます。 `Cat` の `init` と `deinit` でログが出るようにします。

```swift
class Cat {
    init () {
        print("init")
    }
    deinit {
        print("deinit")
    }
}
```

そして下記の関数を実行します。

```swift
func test1() {
    var p = UnsafeMutablePointer<CatHouse>.allocate(capacity: 1)
    defer {
        p.deallocate(capacity: 1)
    }
    p.initialize(to: CatHouse(cat: Cat()))
    p.move()
}
```

`defer` を使って `deallocate` を前置してみました。出力は下記のようになります。

```text
init
deinit
```

さて、ここで、 `move` をしない版を作ってみます。

```swift
func test2() {
    var p = UnsafeMutablePointer<CatHouse>.allocate(capacity: 1)
    defer {
        p.deallocate(capacity: 1)
    }
    p.initialize(to: CatHouse(cat: Cat()))
}
```

すると、deinitがされなくなってしまいました。

```text
init
```

メモリ領域は解放されたものの、そこに書き込まれていた `CatHouse` の破壊処理が行われていないため、それが保持していた `Cat` のカウンタを減らす処理が実行されておらず、メモリリークしてしまったのです。

また、途中で `pointee` を使って古い値を消すテストをしてみます。

```swift
func test3() {
    var p = UnsafeMutablePointer<CatHouse>.allocate(capacity: 1)
    defer {
        p.deallocate(capacity: 1)
    }
    p.initialize(to: CatHouse(cat: Cat()))
    p.pointee = CatHouse(cat: Cat())
    p.move()
}
```

```text
init
init
deinit
deinit
```

正しく2回作られ2回削除されているのがわかります。

では試しに、 `initialize` 前に値を書き込んだらどうなるでしょうか。

```swift
func test4() {
    var p = UnsafeMutablePointer<CatHouse>.allocate(capacity: 1)
    defer {
        p.deallocate(capacity: 1)
    }
    p.pointee = CatHouse(cat: Cat())
    p.initialize(to: CatHouse(cat: Cat()))
    p.move()
}
```

```text
init
init
deinit
```

このように、 `Cat` が1つメモリリークしてしまいました。 `initialize` 前に書き込んだ `pointee` は、 `initialize` の際に **破壊処理無しで上書きされてしまう** ために、 `cat` のカウンタ操作がスキップされてリークしてしまったのです。

そしてこのコードはそれ以前に、 `pointee` への書き込み時に、 **未初期化領域に対して破壊処理を実行している**
 ので、クラッシュの危険もあります。

# ポインタ間の値のやりとりとムーブセマンティクス

アロケートされたメモリが2つあり、片方が初期化済みだったとします。つまり片方には値が存在したとします。この時、存在する方のポインタからもう片方のポインタへ値を移す時に、下記の条件によって2x2通りのパターンがあります。

- 送り先のポインタは初期化済みか、未初期化か
- 送り元のポインタの値はそのままにするか、破棄するか

Swiftでは値型のコピーは高速ですが、例えば `CatHouse` のようにプロパティとして参照型を持っている場合、コピーする時にその参照のカウンタを1増やすという処理が必要になり、そのオーバーヘッドがあります。もし、コピー元の値をその後で破棄するのであれば、その時にカウンタが1減ることになるので、1増えて1減ることになり無駄です。そこで、コピー元の値を破棄すると同時にコピー先に値を移す、という操作があれば、この無駄なオーバーヘッドを除去することができます。これを C++ ではムーブ操作と言うのですが、Swiftのポインタ型にはこのムーブ用のメソッドがあります。

先述したように、未初期化メモリに値を書き込む操作を `initialize` と呼びました。一方、初期化済みメモリに値を書き込む操作を `assign` と言います。これら2つが普通のコピーです。そして、これらのムーブ操作版があり `move` というprefixが付きます。

```swift
public struct UnsafeMutablePointer<Pointee> : Strideable, Hashable {
	...
    public func initialize(from source: UnsafePointer<Pointee>, count: Int)
    ...
    public func moveInitialize(from source: UnsafeMutablePointer<Pointee>, count: Int)
    ...
    public func assign(from source: UnsafePointer<Pointee>, count: Int)
    ...
    public func moveAssign(from source: UnsafeMutablePointer<Pointee>, count: Int)
    ...
}
```

ムーブ版は `source` がミュータブルになります。破棄操作の対象となるからです。

Raw系については初期化・破棄の制御はできません。型が不明だからです。

# メモリ状態とバッファ型

`BufferPointer` 系の型は確保や初期化などのメソッドは持っていません。これらのメモリ操作はポインタの型によって行うようになっていて、バッファはあくまでそこに対するビューのように機能します。

# 型有りと無しの間の変換

型有りのポインタ `UnsafePointer<T>` から 型無しのポインタ `UnsafeRawPointer` への変換はコンストラクタで可能です。

```swift
public struct UnsafeRawPointer : Strideable, Hashable {
	...
    public init<T>(_ other: UnsafePointer<T>)
    ...
}
```

しかし、型無しのポインタから型有りへの変換はコンストラクタではできません。代わりに専用のメソッドが2つあります。

```swift
public struct UnsafeRawPointer : Strideable, Hashable {
	...
    public func bindMemory<T>(to type: T.Type, capacity count: Int) -> UnsafePointer<T>
    ...
    public func assumingMemoryBound<T>(to: T.Type) -> UnsafePointer<T>
    ...
}
```

どうやら先述したstrict-aliasingとの兼ね合いで、 `UnsafeRawPointer` はそのメモリ領域が現在どの型 `T` として扱われているかという事をコンパイラが静的に追跡するようです。これをバインドと呼びます。

`UnsafeRawPointer` としてアロケートした時は未バインドで、これをある型 `T` にバインドするメソッドが `bindMemory` です。それと同時に `UnsafePointer<T>` が返却されます。既に `T` にバインドされているメモリの場合は、 `assumingMemoryBound` メソッドを使えます。

未初期化なメモリをTに型付けしながら初期化する、 `initializeMemory` というメソッドもあります。

このあたりのバインドの状態遷移については、先述した文書の中に記述があります。[Binding memory type](https://github.com/apple/swift-evolution/blob/master/proposals/0107-unsaferawpointer.md#binding-memory-type)

# おわり

ポインタに対する専用構文を使わずに言語機能で必要な機能を提供し、型の情報はジェネリックに扱えてnull安全で、メモリの3状態についても明確に規約が整理された操作メソッドを提供していて、ムーブセマンティクスにも対応できるという事で、とても良くできていると思います。

RustやC++と対比して考えても面白いと思います。これらの言語は1級のポインタが生ポインタで、参照カウントなどがついたスマートポインタはジェネリック型として提供されます。しかしSwiftの場合はこれが逆転していて、1級のポインタがスマートポインタ、生ポインタはジェネリック型として提供されています。アプリを書くのにも使えるが、ローレイヤにも使える言語を設計する上で、この逆転はうまいバランスの取り方だと思います。