C++でプログラミングするときorレビューするとき、constがつけられないか探してしまうようになってしまいました。「staticおじさん※」を真似て「constおじさん」と自虐しています。
Effective C++ にも「使えるときは、必ず const を使おう」と書かれているように、constをうまく使うと、C++のコードが簡潔に、安全になることが期待されます。
…と、えらそうなこと書いてますが、半分以上が自分用のメモです。
※staticおじさん:ググってみると闇が見えます。
値のconst
基本です。
const
と int
の順番が逆でも同じ意味になるのは意外。const int
のほうが良く見るかな。
int a;
a = 1; // const がない場合は自由に変更できる
int b = a;
//const int ca; // 初期化指定子による初期化がないとNG
const int ca = 1;
//ca = 1; // constの変数は変更ができない。NG
int const cb = 1; // int と const が逆でも同じ
ポインタのconst
ポインタにconst
をつける場合は、つける位置によって
- ポインタの中身が変更できない
- ポインタ自体が変更できない
が変化します。両方につけることも可能です。
int* pa; // constなし
pa = &a; // ポインタ自体の変更OK
*pa = 10; // ポインタの中身の変更OK
const int* cpa;
cpa = &a; // ポインタ自体を変更するのはOK
//*cpa = 1; // ポインタの中身を変更するのはNG
//int* const pca; // 初期化がないとNG
int* const pca = &a;
//pca = &b; // ポインタ自体を変更するのはNG
*pca = 10; // ポインタの中身を変更するのはOK
//const int* const cpca; // 初期化がないとNG
const int* const cpca = &a;
//cpca = &b; // ポインタ自体を変更するのはNG
//*cpca = 10; // ポインタの中身を変更するのもNG
ダブルポインタのconst
ここまでくると趣味の領域ですが…
const
をつける位置によって、変更できなくなるところが変わります。
constをつけるつけないの選択が3箇所あるので、つまり合計8パターンあります。
使い所としては、変更しない配列へのポインタをメンバ変数として保持しておく場合とかですかね。
ダブルポインタを使うくらいなら、コレクションクラスを使えという説も。
// 1: constなし
int** ppa;
ppa = &pa;
*ppa = pa;
**ppa = 10;
// 2:
const int** cppa;
//cppa = &pa; // const int** に int** を代入できない
cppa = &cpa; // OK
*cppa = pa;
//**cppa = 10; // NG
// 3:
int* const * pcpa;
pcpa = &pa;
//*pcpa = pa; // 左辺がconst int* なので変更できない
**pcpa = 10; // OK
// 4:
//int** const ppca; // 初期化がないとNG
int** const ppca = &pa;
//ppca = &pa; // NG
*ppca = pa; // OK
**ppca = 10;
// 5:
//const int** const cppca; // 初期化がないとNG
//const int** const cppca = &pa; // const int **const に int** を代入できない
//const int** const cppca = &cpca; // const int **const に const int *const * を代入できない
const int** const cppca = &cpa;
//cppca = &cpa; // NG
*cppca = pa; // OK
//**cppca = 10; // NG
// 6:
//int* const* const pcpca; // 初期化がないとNG
int* const* const pcpca = &pa;
//pcpca = &pa; // NG
//*pcpca = pa; // NG
**pcpca = 10; // OK
// 7:
const int* const* cpcpa;
cpcpa = &pa;
//*cpcpa = pa; // NG
//**cpcpa = 10; // NG
int const* const* cpcpb;
cpcpb = &pa;
int const* * const cppcb = &cpa;
int const* const* const cpcpcb = &pa;
int * * const ppcb = &pa;
// 8:
//const int* const* const cpcpca; // 初期化がないとNG
const int* const* const cpcpca = &pa;
//cpcpca = &pa; // NG
//*cpcpca = pa; // NG
//**cpcpca = 10; // NG
その他const
constおじさんとしてはもっと紹介したいですが、↑の説明がしたかっただけなのでその他は軽く流します。
- const参照
- 関数の中で値を変更する必要が無い場合、値渡しよりもconst参照渡しをすると、メモリコピーが抑えられるので良く使います。基本型の場合は値渡しで良い。
- constメソッド
- クラスのメンバ変数を変更しない保証がされるので良く使います。Getterにconstがついていないとレビューで指摘されます。
- constexpr
- C++11以降。#defineよりもconst変数を使うことはよくありますが、こういう場合はconstexprを使うと良いらしいです。(当方、C++11未経験…)
ぼやき
C# などのconstがない言語で、関数に参照で渡した変数の中身が変わらないことが保証できないのはどうにかならないのでしょうか。constがないと安心して生きていけません。