こんにちは、質問させて下さい。
struct S
{
int i;
};
struct SA
{
private:
int i;
};
とあって、
S s = S();
SA sa = SA();
とした時、s.iは0になりますが、sa.iは初期化されません。
何故なんでしょうか?
処理系にもよるとおもいますが、
構造体の初期化は確か0で初期化されます
で、コンパイラが自動生成するデフォルトコンストラクタはメンバを初期化しません
構造体とクラスは基本一緒だという認識でいいと思いますけど、構造体のメンバはすべ
てアクセスがpublicである
で、ここからは想像なんですが、構造体のメンバに private あることによって、コンパ
イラがクラスとして判別し、デフォルトコンストラクタを自動生成したのではないかな
ぁって。。。
どかな?
hirocco 氏の解釈で正解だが妄想や憶測に頼らずに C++ 言語規格書を読むべし。
規格書は plain old data (C互換クラス) POD というものを定義しており
規格書条文 9.0-4
Visual Studio 2005 の VC++ version 14.00.50727.762 の解釈によると
S は POD に該当し SA は POD でない。
同様、初期化の際の挙動は規格書条文 8.5 が規定しており
1.POD 型 (つまり先の例の S) を S() のように「デフォルト初期化」すると、
デフォルト初期化はゼロ初期化になり、(非静的)全メンバーが0になる。
2.非 POD 型(つまり先の例の SA) を SA() のように「デフォルト初期化」すると
デフォルト初期化は(コンパイラが自動的に作った)コンストラクタを呼び、
SA のコンストラクタは何もしないのでメンバーの初期化もされない。
----
ただ、俺の英語力・日本語力の範囲で規格書 9.0-4 を厳密に解釈すると
SA も POD とみなさざるを得ない。 gcc 開発チームも同じ解釈のようで、
gcc-4.3.4 (cygwin 1.7.7) や gcc-4.5.1 (hppa2.0w-hp-hpux) では SA も
ゼロ初期化される。
SA が POD なのかそうでないのかは非常に微妙っすね・・・
gcc でも VC++ でも boost::is_POD<SA>::value == false になるんだけど。
逆アセンブラ表示でみると、
S s = S();
行は、
1.S()を0に初期化
2.sに上を代入
の様に見えますね。デバッグビルドだからかも知れませんけど。
SA sa = SA();
行は
1.saにSA()を代入
してるだけで、初期化処理は入っていません。
スタックも正しく、変なところを参照している様子もありませんねぇ。
尚
S ss;
SA saa;
の行を入れてみましたが、スタックはされましたが、
使われないのでアセンブラコードになりませんでした(笑)。
つまり、コンストラクタは生成されていませんねぇ。
というか省略されたのですね、たぶん(vv;)。
初期化まわりは,ISO/IEC 14882:1998と同2003で若干異なっています。
規格書の12.6 Initialization / Paragraph. 1が()付きの時に8.5を参照するように書い
てあり,
8.5 Initializers / Paragraph. 7の内容が,
1998: An object whose initializer is an empty set of parentheses, i.e., (),
shall be default-initialized.
2003: An object whose initializer is an empty set of parentheses, i.e., (),
shall be value-initialized.
となっています。
ISO/IEC 14882:1998の場合の挙動はtetrapodさんの書かれている通りですが,
ISO/IEC 14882:2003の場合の挙動は,(8.5 / Paragraph. 5)
> To value-initialize an object of type T means:
> - if T is a class type (clause 9) with a user-declared constructor (12.1),
then the default constructor for T is called (and the initialization is ill-
formed if T has no accessible default constructor);
> - if T is a non-union class type without a user-declared constructor, then
every non-static data member and base-class component of T is value-initialized;
> - if T is an array type, then each element is value-initialized;
> - otherwise, the object is zero-initialized
なので,non-POD structでもゼロ初期化されます (value-initializeは2003版で追加され
た内容)。
考え方によっては,VC++は1998年版を基にnon-PODの初期化を行っていて,
GCCは2003年版を基にnon-PODの初期化を行っている,とも考えられます。
# そもそも規格上SAはPODじゃないのか,というのは私も同意。
同じようなことを私も考えたのですが、
S s;
SA sa;
とすると、今度はどちらも初期化されなくなります。
実用上はコンストラクタを書けば問題はないのですが、
これが、C++の仕様なのか、VC2008独特のものなのか、
はたまたたまたまなのかが分からず投稿した次第です。
おっと、ページ更新せずに投稿してしまいました。
13:32:21のはhiroccoさんに対する返信でしたが、
無視してください。申し訳ないです。
皆さんの詳しい解説になるほど納得です!
このような時には、ちゃんと規格書を頼らないといけませんね・・・。
(規格書に括弧付きの初期化の場合がちゃんと書いてあるのに
関心しました。当然のことなのですが)
ちなみに、最初の例のSAがPODかどうかについては、1998版では、
A POD-struct is an aggregate class that has no non-static data
members of type pointer to member, non-POD-struct,
non-POD-union (or array of such types) or reference,
and has no user-defined copy assignment operator and
no user-defined destructor.
となっていて、この中にアクセス指定に関する記述はなく、
SAはこの条件を満たすので、皆さんがおっしゃっているように
PODに該当すると思います。
おかげでもやもやが解消されました。
ありがとうございました。
もちっと重箱の隅をつついてみるテスト
単に POD と書くと、これは POD types のこと
POD-struct と POD types とは違うもの (先の発言ではあえて区別しなかった)
POD-struct は 9-4 で、既に引用済み
POD types は 3.9-10 で POD-struct 以外も含まれるっつことで。
ただ POD の話は C++ 0x ではかなり変化しているようだ。
特に access specifier の規定が C++ 0x では追加されているみたい。
ISO/IEC 1998 の 1998, 2003 とも 9.2-12 には重要なことが書いてある
・アクセス指定子が挟まらない場合、隣り合う(非静的)メンバーは、
後ろのものが前のものより高位アドレスに配置される
・アクセス指定子で分断されたメンバーの配置順は未規定である
・(アライメント要求により)
隣り合うメンバーが隣接したアドレスに配置されるとは限らない
ため、アクセス指定子が「挟まる」と POD ではなくなってしまう。
提示例 SA は「指定がある」が「挟まっていない」ので POD-struct と解釈すべき。
俺の手元の ISO/IEC 14882:1998 および YuO さん所有の 2003 もともに、
9-4 の記述に access specifier の話が漏れているな・・・