const メンバ関数の落とし穴2012年01月18日 12時14分30秒

C++ のクラスでは、プロトタイプの関数名の後に const をつけることにより、明示的にこの関数はメンバ変数を変更しないと記述できる。

const メンバ関数はメンバ変数を変更しないので、もしコンパイラが違反しているのを見つけられれば、警告をだす。例えば、


% cat const.cpp 
class A
{
    int i;
public:
    A():i(1){}
    void increment() const{ ++i; }
};

int main()
{
    A a;
}

をコンパイルすると、

% CC const.cpp 
const.cpp: In member function 'void A::increment() const':
const.cpp:6: error: increment of data-member 'A::i' in read-only structure

と、オブジェクトファイルが生成されない。それにこの様な簡単な関数であれば、一目瞭然だ。

ところが、なかには一目見ただけでは、メンバ変数が変更されているのが判らないような、副作用によって実際にはメンバ関数が変更される様なコードもある。コンパイラもエラーを認識できないような物もだ。何回か遭遇したことはあるが、昔の事なので、具体的な例を上げられないのが残念だが。

さて、その様な場合どのようなコードが生成されるかと言うと、関数内での変更が、関数を出ると無効になっていた場合が多かった。厄介なのが、メンバ変数の値がずれていったり、酷いときはポインタが無効になっていたりする。症状としては、いつの間にか値が合わなくなっていったり、何も無さそうなところでコアダンプしたりするから厄介だ。加えて、コードを追っているときも const に目がいって、この関数内では値は書き換えられないと思い込んでしまうため、問題点を取り逃しやすい。