その9 クラス内でstatic宣言されたメンバ変数のサイズは0
何だか題目で言いたい事を言ってしまっているのですが(^-^;、ちょっとした覚え書きです。知っている人にしてみると当たり前の事かもしれません。
クラスの中にstaticでメンバ変数を宣言することがあります。これは「クラス変数」などとも呼ばれるクラス内の共通変数となります。この変数はクラスの中に定義され公開されなければクラスの中でのみ使用できる便利な性質を持っています。もちろん当たり前の事ですが、変数なのでそれ自体にはサイズがちゃんとあります。しかし、クラスの中に宣言するので何となくオブジェクトサイズにも影響するかのように思ってしまいます。これは実は全く影響しません。本当に全くです。
試しに、以下に設けた3つのクラスのサイズ比較を行ってみて、「全く具合」を体感してみます:
staticメンバ宣言 struct DUMY
{
char LongText[1000]; // 長いテキストを格納する変数
};
class NormalClass
{
DUMY m_DumyObj;
int a;
};
class StaticClass
{
static DUMY m_DumyObj;
int a;
};
class NullClass
{
int a;
};
この状態で各クラスのサイズをチェックしてみます:
int Normal_Size = sizeof( NormalClass );
int Static_Size = sizeof( StaticClass );
int Null_Size = sizeof( NullClass);
この結果、Normal_Sizeは1004になるのに対して、Static_SizeとNull_Sizeは4になります(これはVS2005でテストしています。int型サイズの環境による違いはあります)。つまり、static宣言されたメンバ変数はオブジェクトサイズにまるで影響しないと言う事でです。当初「ポインタ扱いかもね」などと思っていたのですが、完全にメンバ変数以外の扱いである事がこの比較でわかりました。ちなみに動的に確保されるメモリ内にstatic変数の領域はもちろんそのポインタなどの在り処を表すの痕跡すら入りません。本当に無なんです。
static宣言変数がクラス内スコープを持っているのにオブジェクトには含まれないというのは大変うれしい仕様です。これにより「ダミー変数」をクラス内に設ける事に何の抵抗も無くなります。例えば、次のようなクラスを考えてみます:
Null値ポインタを持つクラス class TestClass
{
protected:
static int DefaultValue; // デフォルト値
int Value;
bool Flag;
public:
TestClass(){ pValue = 100; Flag=true; }
int GetValue()
{
if( Flag )
return Value;
return DefaultValue;
}
};
int TestClass::DefaultValue = 0;
このクラスはstatic宣言されたデフォルト値であるDefaultlValueを持っています。GetValueメソッドはクラスのオブジェクトが保持している値を取得しますが、フラグによりその取得値を切り替えています。つまり、Flagがtureであれば保持しているValueの値を返しますが、Flagがfalseの場合はDefaultValueを返します。こういう使い方は「フラグが降りている時に不定の値を返さない事を保証する」という意味で重要です。
上のクラスのオブジェクトが10000個くらいあるとしたら、int型とは言え全てのオブジェクトにデフォルトの値を持たせるのは非常に無駄です。しかしstatic宣言された値であればわずか4バイトのメモリ使用で済みます。しかもオブジェクトのサイズにその変数は全く含まれない、さらに共有変数ですからコピーの対象にもならない、そしてprotected宣言されているのでクラス以外は触れないとなりますと、本当に安心してstatic宣言変数を使えるようになります。
クラスにどうしてもデフォルト値(Nullオブジェクト)を設けたい。そんな時にはstatic宣言変数を大いに利用しましょう〜。