2014年5月12日月曜日

[c++][gcc] constメンバ関数の中でメンバ変数を書き換えるには

C++において、一般的に定数宣言の目的で使用されるconst修飾子ですが、メンバ変数、メンバ関数、引数、返値にも宣言できることはご存知でしょうか。
適切に利用することで、以下のようなメリットが得られます。
  • API仕様がより明確になる
  • コードの可読性・メンテナンス性があがる

これらのメリットを享受すべくconst修飾子を積極的に利用していたのですが、まれにconstメンバ関数の中で、メンバ変数を書き換えたい、もしくは、メンバ変数の関数を呼び出したい、といったケースが発生したことがありました。
これまではconst関数の中でメンバ変数の値は参照のみで書き換えはできないと思っていたのですが「C++のためのAPIデザイン」という書籍を読みmutable修飾子が用意されていることを知りました。

const関数の中でメンバ変数を書き換えようとすると以下のようなエラーになります。

const_test.cpp: In member function 'void ConstTest::constFunc(int) const':
const_test.cpp:11:9: error: assignment of member 'ConstTest::m_val' in read-only object
   m_val = val;
         ^
const_test.cpp:12:23: error: passing 'const NotConst' as 'this' argument of 'void NotConst::normalFunc()' discards qualifiers [-fpermissive]
   m_normal.normalFunc();
                       ^
これは以下のコードをコンパイルしたときのエラーです(gcc 4.8.2)。
class NotConst
{
public:
 void normalFunc() /*const*/ {}
};
class ConstTest
{
public:
 void constFunc(int val) const
 {
  m_val = val;
  m_normal.normalFunc();
  return;
 }
private:
 /*mutable*/ int m_val;
 /*mutable*/ NotConst m_normal;
};
15行目と16行目でコメントアウトしているmutable修飾子を有効にすると、エラーなくコンパイルが通るようになります。mutable修飾子が付与されている変数を見かけたときには「const宣言されたオブジェクトでも変更されることがありますよ」と理解しましょう。

ちなみに後者のエラーは、NotConst::normalFunc()をconst関数に変更することでも修正が可能です。normalFunc()の仕様としてconst関数が適切なのであれば、mutable宣言を用いるのは避けてconst関数化すべきです。

0 件のコメント:

コメントを投稿