C++と色々

主にC++やプログラムに関する記事を投稿します。

POD型とnon-POD型

2012/3/19追記
この記事の情報はC++03のものです。C++11ではPOD型の定義が異なっています。

POD(Plain Old Data)型とはコンストラクタコンパイラが自動生成したデフォルトコンストラクタしか持たいない型のことです。int型やdouble型などの組み込み型、またはメンバ変数がPOD型しか持たない構造体やクラスもPOD型です。
一方自分で定義したコンストラクタを持つ型をnon-POD型と言います。メンバ変数にnon-POD型を持った構造体やクラスは自分自身はデフォルトコンストラクタしか持っていなくてもnon-POD型となります。

POD型のデフォルトコンストラクタは全てのメンバ変数を0で初期化し、メンバ変数が構造体やクラスの場合さらにその構造体やクラスのメンバ変数を0で初期化します。

non-POD型は宣言時や実体が作られる時にコンストラクタは呼ばれるが、POD型は宣言時や実体を作る時にコンストラクタは呼ばれません。POD型は明示的に呼ぶ必要があります。

#include <iostream>
using std::cout;
using std::endl;

//POD型
struct Hoge
{
	int a;
};

//non-POD型
struct Foo
{
	Foo() : a() {}
	int a;
};

int main()
{
	Hoge* hoge = new Hoge;//コンストラクタは呼ばれていないのでaは未初期化!
	cout << hoge->a << endl

	Foo* foo = new Foo;//コンストラクタは呼ばれるのでaは初期化される
	cout << foo->a << endl;

	delete hoge;
	delete foo;

	return 0;
}

実行結果例

-842150451
0
続行するには何かキーを押してください . . .

POD型のコンストラクタを呼ぶには明示すれば良いです。

#include <iostream>
using std::cout;
using std::endl;

//POD型
struct Hoge
{
	int a;
};

int main()
{
	Hoge* hoge1 = new Hoge;//コンストラクタは呼ばれない
	cout << hoge1->a << endl;

	Hoge* hoge2 = new Hoge();//コンストラクタを明示。呼ばれる
	cout << hoge2->a << endl;

	delete hoge1;
	delete hoge2;

	return 0;
}

実行結果例

-842150451
0
続行するには何かキーを押してください . . .

配列の場合は Hoge* hoge = new Hoge[1](); と書けばいい。

また、non-POD型の初期化ではnon-POD型のメンバ変数のコンストラクタは自動で呼ばれ、POD型のメンバ変数のデフォルトコンストラクタは呼ばれません。

#include <iostream>
using std::cout;
using std::endl;

//non-POD型
struct Hoge
{
	Hoge() : a() {}
	int a;
};

//non-POD型
struct Foo
{
	int a;
	Hoge hoge;
};

int main()
{
	Foo* foo = new Foo;
	cout << foo->a << endl;	//初期化されていない
	cout << foo->hoge.a << endl;//初期化されている

	delete foo;
	return 0;
}

実行結果例

-842150451
0
続行するには何かキーを押してください . . .

POD型のコンストラクタを呼ぶにはやはり明示すれば良いです。
2通り書けます。
1つめ

#include <iostream>
using std::cout;
using std::endl;

//non-POD型
struct Hoge
{
	Hoge() : a() {}
	int a;
};

//non-POD型
struct Foo
{
	int a;
	Hoge hoge;
};

int main()
{
	Foo* foo = new Foo;
	foo->a = int();		//明示的にコンストラクタを呼ぶ
	cout << foo->a << endl;		//初期化されている
	cout << foo->hoge.a << endl;	//初期化されている

	delete foo;
	return 0;
}

実行結果

0
0
続行するには何かキーを押してください . . .

2つめ

#include <iostream>
using std::cout;
using std::endl;

//non-POD型
struct Hoge
{
	Hoge() : a() {}
	int a;
};

//non-POD型
struct Foo
{
	//コンストラクタの初期化子リストで明示的にコンストラクタを呼ぶ
	Foo() : a() {}

	int a;
	Hoge hoge;
};

int main()
{
	Foo* foo = new Foo;
	cout << foo->a << endl;		//初期化されている
	cout << foo->hoge.a << endl;	//初期化されている

	delete foo;
	return 0;
}

実行結果

0
0
続行するには何かキーを押してください . . .

参考文献
ロベール:"ロベールのC++入門講座"、毎日コミュニケーションズ(2007)