LoginSignup
153
149

More than 5 years have passed since last update.

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

Last updated at Posted at 2017-12-06

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

図解(凡例)

int val = 123;    // 普通の変数
int* ptr = &val;  // ポインタ(pointer)
int& ref = val;   // 参照(reference)
const int cval = 45;  // 定数(constant)

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

legend.png

const × ポインタ型

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

int       *       ptr1 = &val;
const int *       ptr2 = &val;
int const *       ptr2 = &val;  // 上に同じ
int       * const ptr3 = &val;
const int * const ptr4 = &val;
int const * const ptr4 = &val;  // 上に同じ

constポインタの図解

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

ptr-const1.png

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

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

constポインタと定数の関係

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

int       *       ptr5 = &cval;  // NG: コンパイルエラー!!
const int *       ptr6 = &cval;  // OK
int       * const ptr7 = &cval;  // NG: コンパイルエラー!!
const int * const ptr8 = &cval;  // OK

ptr-const2.png

const × 参照型

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

int       & ref1 = val;
const int & cref1 = val;
int const & cref1 = val;  // 上に同じ

const参照の図解

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

ref-const1.png

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

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

const参照と定数の関係

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

int       & cref1 = cval;  // NG: コンパイルエラー
const int & cref2 = cval;  // OK

ref-const2.png

おしまい。


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

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

153
149
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
153
149