const の取り扱い

constメンバ関数は重要 - Faith and Brave - C++で遊ぼう より.

const と言うキーワードは C++ の中でも重要な位置を占めています.そのせいもあってか,「コメントで IN とか OUT とか書く位なら const 使えバカ」「Effective C++ に載ってるんだから const 使え」と言ったような手厳しい意見も聞かれます.一方で,その使用範囲の広さからか「const って良く分らないし・・・」「要は,(プログラマが)気を付けてれば良いんでしょ?」「こまけぇこたぁいいんだよ!!」と言った声も聞かれます.

今回は,そんな const について少し記述してみます.

おさらい

#include <iostream>
#include <string>

/* ------------------------------------------------------------------------- */
//  person
/* ------------------------------------------------------------------------- */
class person {
public:
    person() : name_() {}
    
    // メンバ変数の内容を変更しないので const にする.
    const std::string& get_name() const {
        return name_;
    }
    
    void set_name(const std::string& cp) {
        name_ = cp;
    }
    
private:
    std::string name_;
};

/* ------------------------------------------------------------------------- */
/*
 *  say_something
 *
 *  person クラスの内容を参照するだけなので,const にする.
 */
/* ------------------------------------------------------------------------- */
void say_something(const person& you) {
    std::cout << "Hello, " << you.get_name() << std::endl;
}

/* ------------------------------------------------------------------------- */
//  main
/* ------------------------------------------------------------------------- */
int main(int argc, char* argv[]) {
    person a;
    a.set_name("clown");
    say_something(a);
    
    return 0;
}

const は,主に二つの場面でよく使用されます.一つは,関数の引数に付ける場合(例では,say_something() の引数の部分).この場合は,その引数の内容は参照するだけで変更されない(変更できない)事が保障されます.

もう一つは,メソッド(メンバ関数)に付ける場合(例では,person クラスの get_name() の部分).この場合は,そのメソッドはクラスが保持しているメンバ変数の内容を変更しない(変更できない)事が保障されます.

「良く分らないから const は使わない」と言うスタンス

さて.「const は良く分らないから使わない」と言う人は結構多いように思います.このスタンスを貫いた場合どうなるでしょう?例えば,上記の person クラスの const を全て取り払ってみます.すると,以下のようなコンパイルエラーが出力されます.

$ g++ -Wall example_const.cpp
example_const.cpp: In function 'void say_something(const person&)':
example_const.cpp:32: error: passing 'const person' as 'this' argument of
'std::string& person::get_name()' discards qualifiers

const には(参照先の内容を変更できないと言う性質を考えると分かりますが)「const 付の引数で渡されたインスタンスは,const 付のメソッドしか呼ぶことができない」と言う特徴(制約)があります.このため,「良く分らないから」などの理由で const 付のメソッドをまったく定義しなかった場合,そのクラスのインスタンスを const 付の引数で受け取ったときに「受け取った側は何もできない(全てのメソッドを利用できない)」と言う状況が発生します.

(クラス利用者側が)これを回避するには,多く場合「引数部分の const を取り除く」と言う対処をする事になります(上記の例では,void say_something(person& you) にする).したがって,クラスが適切に const 付のメソッドを提供していないと,そのクラスを利用する側も連鎖的に const を使用できない(「使用しない」ではなく「使用できない」)事になってしまいます.

プログラムが一人で完結しているのであれば,「const はよく分らないから使わない」でも良いかもしれません(あまり良くないとは思いますが).しかし,複数人で開発したりライブラリとして提供したりするなど,自分の作成したクラスが他人に使用される場合には,const 付メソッドを適切に提供しないと他人に大きな影響を与えることになります(対処療法的な処置を強いる).そうならないためにも,各メソッドの性質を良く検討し適切に const を付ける必要があります.

Reference