結果だけでなく過程も見てください

たい焼きさんの日々の奮闘を綴る日記です。

C++では定数はヘッダではなくソースファイルに書こう


特定の意味をもつリターンコード等の固定値は
ある程度1つのヘッダに集中して定義すると思います。


例えば、C言語ではマクロ変数を使用して以下のように定義します。
人によってはC++でも以下のように定義するかもしれません。

#define RETCODE_SUCCESS (0)
#define RETCODE_FAIL    (1)
#define RETCODE_WARN    (2)


マクロ変数は、コンパイラではなくプリプロセッサで置き換えられるので
コンパイラはRETCODE_SUCCESSやRETCODE_FAILなどのシンボルを
認識することができません。


これはプログラム上の各所にマジックナンバーが散りばめられる
ことになり、デバッグ時などには都合がよろしくないということで、
C++では以下のように定義することを推奨しています。


このへんはEffective C++の2項あたりにも書いてたと思います。


ヘッダに変数を宣言。

struct CConstParam
{
  static const int RETCODE_SUCCESS;
  static const int RETCODE_FAIL;
  static const int RETCODE_WARN;
};


ソースファイルに実体と初期値を定義。

const int CConstParam::RETCODE_SUCCESS = 0;
const int CConstParam::RETCODE_FAIL    = 1;
const int CConstParam::RETCODE_WARN    = 2;


上記のコードには、定数変数をコンパイラで処理させる以外にも
重要な意味があります。


それは、ヘッダには宣言のみが記述されており
実際の値は含まれていないため値を変更しても
ヘッダをincludeしているソースファイルの再コンパイル
走らないという点です。


例えばRETCODE_WARNの値を2から3に変更することになったとします。
従来の方法ではヘッダ内の記述が変化するので、
このヘッダをincludeしているソースファイルの内容が全て
変化することになり、全てのソースファイルのコンパイル
発生してしまうのです。


しかしソースファイルに実体と値を書く方法では定数の値を変更しても
ヘッダには何の変化もないため、コンパイルしなおす必要はありません。


自分はよくテスト用にゲームの固定値(キャラクターのサイズや
メニューの細かい位置など)をソース上に記載しているのですが
すべてヘッダに書いていたころは、少しでも値を変更すると
コンパイルが走り、そのコンパイル時間が1〜2分になっていました。


正直、徐々に値を動かして画面のデザインを見るようなテストのときは
めちゃくちゃ不便です^^;


そういう意味もあって、ソースファイルに実体を値を書く方法は
優れており、またマクロ変数の煩わしいカッコ地獄からも解放される
ことになると思います。