図解：constとポインタと参照

本記事は「ポインタ／参照と`const`キーワードについて、なんとなく分かってきたかも？」という学習ステージの方が、const修飾の役割を **イメージできる** ような理解を目指しています。


# 図解(凡例)
```c++
int val = 123;    // 普通の変数
int* ptr = &val;  // ポインタ(pointer)
int& ref = val;   // 参照(reference)
const int cval = 45;  // 定数(constant)
```

本記事では、上記C++ソースコードに対応する図示を次のルールで行います。"白色の箱"が普通の変数(`cval`)やポインタ型変数(`ptr`)を、"赤色の箱"が定数(`cval`)を、"黄色タグ"が参照型変数(`ref`)をそれぞれ表します。箱の中身は、各変数が保持している値に対応します。ポインタ型変数は"差し先変数のアドレス値"を保持しますが、分かりやすさのため矢印(→)にて表現します。参照型変数についても同様です。[^ref-shape]

![legend.png](https://qiita-image-store.s3.amazonaws.com/0/6657/f84aa757-4d26-12b7-53a2-d17c5f9385ed.png)

[^ref-shape]: 参照型変数だけが"箱"形をしていないことに気づいたでしょうか？C++言語では、参照型変数と通常変数・ポインタ・定数が明確に区別されることを反映しています。通常変数・ポインタ・定数はメモリ上に実体が存在するため、本文中では"箱"のイメージを用いました。一方の参照型変数はその形状が示す通り、別の実体に対するタグ(tag)／別名(alias)と解釈できます。（厳密な議論は[こちらの記事](http://d.hatena.ne.jp/yohhoy/20171128/p1)を参照）


# const × ポインタ型
ポインタ型変数の宣言では、**アスタリスク(`*`)の前または後ろ**に`const`キーワードを配置できます。つまり`const`の有無に応じて4種類のポインタ型変数が存在します。なお先頭アスタリスク(`*`)よりも前では、`const int`／`int const`いずれの書き方でも同じポインタ型となります。お好みの順序で利用ください。

```c++
int       *       ptr1 = &val;
```

```c++
const int *       ptr2 = &val;
int const *       ptr2 = &val;  // 上に同じ
```

```c++
int       * const ptr3 = &val;
```

```c++
const int * const ptr4 = &val;
int const * const ptr4 = &val;  // 上に同じ
```

## constポインタの図解
それぞれのポインタ型と、const修飾の関係を図示します：

![ptr-const1.png](https://qiita-image-store.s3.amazonaws.com/0/6657/5c8f4c5d-d51a-a290-0792-cc7a629093ee.png)

- アスタリスク(`*`)の前に`const`を置いた場合、ポインタ型変数`ptrN`を**介して**差し先の値`42`を書き換えることはできません。（図中では"赤枠"で表現）
- アスタリスク(`*`)の後ろに`const`を置いた場合、ポインタ`ptrN`は**定数**となります。つまり差し先の変数／矢印が向かう先は固定です。

前者では、あくまで “このポインタを経由した” 値の書き換えが禁止されるだけであり、このポインタ経由でなければ値は書き換え可能です。


## constポインタと定数の関係
先ほどはポインタの指す先が普通の変数でしたが、ポインタの指す先が定数(`const int`)の場合は次の関係になります；

```c++
int       *       ptr5 = &cval;  // NG: コンパイルエラー!!
```

```c++
const int *       ptr6 = &cval;  // OK
```

```c++
int       * const ptr7 = &cval;  // NG: コンパイルエラー!!
```

```c++
const int * const ptr8 = &cval;  // OK
```

![ptr-const2.png](https://qiita-image-store.s3.amazonaws.com/0/6657/34b7c6f7-9e08-7cc1-2013-eb218b96aa71.png)


# const × 参照型
参照型変数の宣言では、**アンパサンド(`&`)の前にのみ**`const`キーワードを配置できます。つまり`const`の有無に応じて2種類の参照型変数が存在します。ポインタ型と同様に`const int`／`int const`は順不同です。[^ref-types]

[^ref-types]: 古き良きC++03時代には、ある型`T`に対する参照型は1種類(`T &`)しか存在しませんでした。C++11以降のモダンなC++言語では、従来からの左辺値参照型(`T &`)と新しい右辺値参照型(`T &&`)とで2種類の参照型が存在します。`const`キーワードも考慮すると、厳密には4種類の参照型(`T &`,`const T &`,`T &&`,`const T &&`)となるのです。ただし、本記事範囲では右辺値参照型(`T &&`)へ言及する必要性がないため、昔ながらの左辺値参照型(`T &`)のみを対象としています。

```c++
int       & ref1 = val;
```

```c++
const int & cref1 = val;
int const & cref1 = val;  // 上に同じ
```

## const参照の図解
それぞれの参照型と、const修飾の関係を図示します：

![ref-const1.png](https://qiita-image-store.s3.amazonaws.com/0/6657/334d8dff-db40-2410-235a-d03855153445.png)

図示では省略しましたが、アンパサンド(`&`)の後ろに`const`キーワードを書くことはできません。仮に書けた場合は「参照型変数の参照先は固定」に相当しますが、もともと参照型変数の参照先を変更することは不可能ですから、コンパイルエラーとして扱われます。

```c++
int       & const ref = val;   // NG: コンパイルエラー
//          ^^^^^
const int & const cref = val;  // NG: コンパイルエラー
//          ^^^^^
```

## const参照と定数の関係
参照の指す先が定数(`const int`)の場合は次の関係になります；

```c++
int       & cref1 = cval;  // NG: コンパイルエラー
```

```c++
const int & cref2 = cval;  // OK
```

![ref-const2.png](https://qiita-image-store.s3.amazonaws.com/0/6657/79391290-cbe3-6642-fad2-a3c47a5d7476.png)

おしまい。