初学者が学ぶ生ポインタとunique_ptrの違い、操作方法

# はじめに
この記事は普段生ポインタを使ってコードを書いていた自分がスマートポインタに乗り換えるために勉強したことをまとめたものです。
間違いがあればコメントなどで教えていただけると幸いです。

# スマートポインタ
C++で動的にヒープ領域中のリソースを確保する方法の1つとして生ポインタと`new`演算子を使うものがあります。

```cpp
int main() {
  int *p = new int[10000]; // メモリを確保
  memset(p, 2, 10000);
  for (int i = 0; i < 10000; ++i) {
    cout << p[i] << endl;
  }
  delete[] p; // 解放
}
```

非常にオーソドックスな方法ですが、`new`後は`delete`でリソースを解放する必要があります。
C++ではJavaなどで採用されているGCの仕組みはないため、コードを書く人が責任を持ってメモリを解放しなければいけません。これを忘れるとメモリリークの原因になります。

C++11以降では**スマートポインタ**を使うことでリソースの解放をプログラムに任せられるようになりました。
スマートポインタは、動的に割り当てられたオブジェクトへのポインタを保持し、スマートポインタが所属するスコープを抜けると自動的にリソースが解放されます。

スマートポインタは標準ライブラリでは4種類用意されています。

|スマートポインタ||
|---|----|
|std::unique_ptr|指定したヒープ上のリソースへの所有権を唯一持つポインタ。|
|std::shared_ptr|1つのヒープ上のリソースを複数のオブジェクトが共有できるポインタ。|
|std::weak_ptr|shared_ptrを監視するポインタ。shard_ptrによる循環参照を防ぐ。|
|std::auto_ptr|C++11以前のスマートポインタ。コピーによって所有権が移ってしまう。C++11で非推奨、C++17で削除。|

本記事では`unique_ptr`についてまとめます。

# unique_ptrの基本的な使い方
## unique_ptrとは
**unique_ptr**はリソースへの所有権をただ1つ持つポインタです。unique_ptrが参照しているポインタをコピーしようとするとエラーが発生します。もし新たなポインタにunique_ptrが持つリソースを参照させたいときは、後述する**ムーブ**または**ムーブコンストラクタ**を使用して明示的にリソースの所有権を**譲渡**してもらう必要があります。

## コンストラクタ
unique_ptrの宣言方法は主に4つです。

```cpp:constructor
std::unique_ptr<int> up1; // (1)空のユニークポインタを宣言する

int *p = new int;
std::unique_ptr<int> up21(p); // (2)生ポインタの所有権を受け取る
std::unique_ptr<int> up22(new int); // こう書いても良い

std::unique_ptr<int> xp3(new int);
std::unique_ptr<int> up3(std::move(xp3)); // (3)std::moveで他のユニークポインタが所有するポインタを受け取る
up3 = std::move(xp3); // これでも良い(ムーブ代入)

std::unique_ptr<int> up4 = nullptr; // (4)nullptrで初期化 
```

もちろんテンプレートには`int`以外の型を指定することもできます。

また`T[]`型もunique_ptrで宣言することができます。

```cpp:constructor
std::unique_ptr<int[]> up5(new int[10]); // (5)int[10]を持つユニークポインタ
```

C++14以降ではヘルパー関数 `std::make_unique`を使ってunique_ptrを構築できます。

```cpp:make_unique
// T型 引数が要素になる
std::unique_ptr<int> up6 = std::make_unique<int>(5); // (6)cout << *up6 << endl; // 5 となるユニークポインタを構築
// T[]型 引数の要素数を持つ配列になる
std::unique_ptr<int[]> up7 = std::make_unique<int[]>(10); // (7)要素数10のint[]を構築
```

## unique_ptrへのアクセス
`unique_ptr<T>`では`operator*, operator->`が定義されているので、生ポインタと同じようにリソースにアクセスできます。

```cpp:operator*
std::unique_ptr<int> up = std::make_unique<int>(5);
std::cout << *up << "\n"; // 5

std::unique_ptr<std::vector<int>> uv = std::make_unique<std::vector<int>>(10);
uv->at(2) = 1;
std::cout << uv->at(2) << "\n"; // 1
```

`unique_ptr<T[]>`では`operator[]`が定義されているため、`[]`によるアクセスも可能です。

```cpp:operator[]
std::unique_ptr<char[]> up = std::make_unique<char[]>(10);
up[5] = static_cast<char>(97);
std::cout << up[5] << "\n"; // 'a'
```

## リソースの解放
明示的なリソースの解放は `reset` で行います。

```cpp:reset
std::unique_ptr<char[]> up = std::make_unique<char[]>(10);
up.reset(); // リソースの解放
up.reset(new char[5]); // リソースを解放して、新たに要素数5のchar[]を所有させる。
```

## 生ポインタの取得(get, release)
どうしてもunique_ptrから生ポインタが必要になった場合(CのAPIを呼ぶ場合など)には`get`, `release`を使用します。
ただし、get, releaseには次のような違いがあります。

|メソッド|説明|
|---|---|
|get|生のポインタを取得する。**unique_ptrは所有権を手放さない。**|
|release|生のポインタを取得する。**unique_ptrは所有権を手放す。**|

`get`ではunique_ptrは所有権を手放さないので、もし生ポインタdeleteしてしまうと二重でポインタを解放してしまうことになります。
`release`では所有権がなくなるので、しっかりポインタを解放する必要があります。

```cpp:get
#include <iostream>
#include <memory>
using namespace std;

int main() {
    unique_ptr<int> p(new int(2));
    int* t = p.get();
    *t = 1;
    cout << *t << endl;
    delete t;
// *** Error in `./prog.exe': double free or corruption (fasttop): 0x00000000019bf1b0 ***
}
```

```cpp:release
#include <iostream>
#include <memory>
using namespace std;

int main() {
    unique_ptr<int> p(new int(2));
    int* t = p.release();
    *t = 1;
    cout << *t << endl;
    delete t; // ok(リソースの解放はコーダーに委ねられる)
}
```

## swap
2つのunique_ptrの所有しているリソースを入れ替えることができます。

```cpp
std::unique_ptr<int> up1(new int(5));
std::unique_ptr<int> up2(new int(3));
std::swap(up1, up2);
std::cout << *up1 << "\n"; // 3
std::cout << *up2 << "\n"; // 5
```

## 他にも
自分は完全に理解できていませんが、他にもデリータを返す`get_deleter`や多数の演算子が定義されています。
より詳細な解説は人類の叡智が詰まった以下のサイトをどうぞ。

[cpprefjp](https://cpprefjp.github.io/reference/memory/unique_ptr.html)
[cppreference.com](https://ja.cppreference.com/w/cpp/memory/unique_ptr)

#まとめ
* リソースを自動的に解放してくれるスマートポインタ。種類はunique_ptr, shared_ptr, weak_ptr, auto_ptrの4つ。（1つは非推奨）
* ほぼ生ポインタのように操作できる。
* もし生ポインタが必要になったら, get, release。ただしリソースの所有権はだれが持っているかを忘れないこと。

# 参考文献
[C++11スマートポインタ入門](https://qiita.com/hmito/items/db3b14917120b285112f)

挙動を試すのにいっぱい使わせてもらいました。
[Wandbox](https://wandbox.org/permlink/zus0LvZbM0BBiWR9)