技術的雑談-ポインタ変数の前constと後constの違い
環境
- 多分C++全般
- 確認したのはGCC4.3
現象
- 「const Hoge* pPointer」と「Hoge* const pPointer」の違いに疑問を持った時
説明
C++で変数が不変である事を宣言するconstというものがありますが、良く見ると2通りの書き方があることがわかります。
そして、それによって効能が変わってきます。
ここでは「Hoge」はclass名だとします。仮に下記のようなヘッダーを持つとします。
class Hoge { public: // コンストラクタ Hoge(std::string& rName); // デストラクタ ~Hoge(); // オブジェクトの状態を変更しないメソッド void methodA() const; // オブジェクトの状態を変更するかもしれないメソッド void methodB(); private: 〜省略〜 }
クラス名の前にconst
const Hoge* pPointer;
これは「pPointerが指すオブジェクトHogeが不変である、不変でなくてはならない」という意味になります。
実際の動作としては、
- pPointerのポインタ値は後から変更できる。(pPointer = new Hoge("other"); は可能)
- pPointerが指すObjectの内容や状態を変える動作は実行できない。pPointerの指すObject状態を変更する動作とは、「const宣言のされていないHogeクラスのメソッドの実行」を指す。
- methodA()は実行できる。
- methodB()は実行できない。宣言にconstがついていないので、コンパイラによって「このメソッドはオブジェクトの状態を変えてしまう」と判断される。(コンパイル時にエラーになる)
変数名の後にconst
Hoge* const pPointer = new Hoge("new");
これは「pPointer自体が不変である、不変でなくてはならない」という意味になります。
実際の動作としては、
- pPointerのポインタ値は後から変更できない。宣言時に初期化が必須。(コンパイルエラーになる。)
- pPointerが指すObjectの内容や状態を変える動作は実行できる。例の場合はmethodB()も実行できる。
両方にconst
const Hoge* const pPointer = new Hoge("both");
あんまり見かけませんが、こういう宣言もできます。
これは「pPointerが指すオブジェクトHogeが不変である、不変でなくてはならない」+「pPointer自体が不変である、不変でなくてはならない」という意味になります。
ガチガチですね。
- pPointerのポインタ値は後から変更できない。宣言時に初期化が必須。(コンパイルエラーになる。)
- pPointerが指すObjectの内容や状態を変える動作は実行できない。pPointerの指すObject状態を変更する動作とは、「const宣言のされていないHogeクラスのメソッドの実行」を指す。
- methodA()は実行できる。
- methodB()は実行できない。宣言にconstがついていないので、コンパイラによって「このメソッドはオブジェクトの状態を変えてしまう」と判断される。(コンパイル時にエラーになる)
このように、constの位置によって挙動が変わってくるので注意して下さい。
尚、これらのconst縛りはconst_cast<>()によって変更する事はできますが、キャストを本当にしても良いのかどうか十分に検討しましょう。
deleteの挙動
しかしながら、上記の3状態どれであってもdeleteはできてしまいます。
特に下の2つの宣言をした場合、ポインタの値が変更できないのでポインタにNULLをセットしてプログラム的に無効であることをチェックする事ができません。
delete以降にそのポインタのポイント先にアクセスすると即死亡です。
御注意下さい。
履歴
2009/03/14 -- 初版
技術的雑談へ戻る