HEXA BLOG

プログラム

HEXA BLOGプログラム2009.5.27

クラスのメンバ初期化時の注意事項

こんにちは、イワムーですわーい(嬉しい顔)
今日はプログラムの話でもしてみようと思いますパンチ
C++ でクラスのデータメンバ(メンバ変数)の値を初期化したい場合、皆さんはどのように実装されていますか?
様々な方法が考えられると思いますが、
memset() の使用に関しては時として注意が必要になりますexclamation×2
#include < string.h >
void *memset(void *s, int c, size_t n);

memset() は s で示されるメモリ領域の先頭から n バイトを c で埋める関数です。
文字を格納するバッファを特定の文字で埋めておきたい場合など、便利ですよねペン
char buff[6];
memset(buff,’H’,sizeof(buff));

同様にクラスオブジェクトに対しても memset() は使用できますが、そのクラスが virtual メソッドを含んでいた場合は注意が必要ですexclamation
#include < string.h >
#include < memory.h >
#include < iostream >
class Hexa {
public:
   Hexa(){}
   ~Hexa(){}
   virtual void setStr(void){}
protected:
   char _str[0x10];
};
class Hexa2 : pubilc Hexa {
public:
   Hexa2(){}
   ~Hexa2(){}
   void setStr(void){ strcpy(_str,”hexadrive”); }
   char* drawStr(void){ return _str;}
};
int main(void)
{
   Hexa2* pHexa = new Hexa2();
   memset( (void*)pHexa, 0, sizeof(Hexa2) );
   pHexa->setStr(); // ここでクラッシュする
   cout<drawStr();
   retuen 0;
}

このプログラムを実行するとsetStr()を呼び出す時点でクラッシュしますあせあせ(飛び散る汗)
なぜなら setStr() が virtual メソッドになっているからです。
C++ではクラスのメソッドに virtual キーワードをつけて宣言する(仮想関数)と、自動的に「関数ポインタの配列」(のポインタ)がメンバ変数領域に作られます。
これを仮想関数テーブル(vtable)と呼びますひらめき
仮想関数テーブルの詳細はこちら
実行時に動的に呼び出すメソッドを決める必要がある、virtual メソッドはこのvtableで実現されています。
通常はプログラマーはvtableにはアクセスできませんが、memset()をvirtualメソッドを持ったクラスオブジェクトに適用してしまうと、上記例ではvtableの中身までゼロクリアされてしまうため、アドレスがゼロになっている関数を呼び出そうとした時点でクラッシュしてしまうのですバッド(下向き矢印)
(コンパイラの最適化オプション等の影響でクラッシュしない場合もあります)
ではどうやってメンバを初期化したら良いのかというと、やはりデフォルトコンストラクタや初期化メソッドで各メンバの初期値を入れるのが良いのではと思いますわーい(嬉しい顔)
クラスのメンバ初期化時には意識してみてくださいねるんるん

RECRUIT

大阪・東京共にスタッフを募集しています。
特にキャリア採用のプログラマー・アーティストに興味がある方は下のボタンをクリックしてください

RECRUIT SITE 

NEWS