C++0xのPODの定義をまとめてみた。ただし、C++0xでは、memcpyでコピーして、各データメンバーの状態が保証されるためには、、trivially copyable classであればいい。
PODは、trivial classかつstandard-layout classであること。
さらに、非PODな非staticデータメンバーを持たないこと。
trivially copyable class
ユーザー定義のコピー、ムーブのコンストラクタと代入演算子がないこと。
デストラクタがtrivialであること。
trivial class
trivially copyable classに加えて、コンストラクタもtrivialであること。
trivialであるということは、ユーザー定義ではないことと、delete化(C++0xの新しい機能)されていないこと。
コピー、ムーブコンストラクタがtrivialであるためには、仮想関数や仮想基本クラスを持たないという条件も必要になる。
standard-layout class
standard-layout classではない非staticなデータメンバーを持たないこと。
仮想関数、仮想基本クラスがないこと。
非staticなデータメンバーは、同じアクセス指定であること。
standard-layout classではないクラスを継承していないこと。
継承をしている場合、一番上の派生クラスは非staticなデータメンバーを持たず、基本クラスのどれかひとつだけが、非staticなデータメンバーを持つこと。
非staticなデータメンバーを持つ同じクラスを、複数継承しないこと。
最後の継承に関する例。
struct Base { int x ; } ; struct POD : Base {} ; struct NonPOD : Base { int x ; } ;
PODとなるためには、一番上の派生クラスは、非staticなデータメンバーを持っていてはならない。
実際、これまでPODに拘る理由というのは、memcpyなどで単純なバイト列のコピー出来るかどうかである。これは、C++0xでは、trivially copyable classであれば保証される。
つまり、memcpyでコピー出来るクラスの制限は、だいぶ緩和される。まず、コンストラクタがあってもいいし、継承していてもいい。standard-layout classである必要はない。派生クラスと基本クラスが、共に非staticなデータメンバーをもっていても構わない。アクセス指定もできる。
いくつか間違いと思われる記述が見られたので、 n3092 と照らし合わせ
ReplyDeleteながらの突っ込みを入れておきます。
> PODは、trivial classかつstandard-layout classであること。
"POD class とは~" ですね。 POD はこのほかに Scalar type や、それらの
配列も含みます。
> trivially copyable class
実際にはコピー、ムーブコンストラクタと代入演算子が trivial でなければ
ならず、そのためにはすでに挙げられている条件に加えて、クラスが仮想関数も
仮想基底クラスも持たないこと、以上の条件をすべての基底クラスと
非 static データメンバも満たすこと、が必要になるようです。
> コンストラクタもtrivialであること。 trivialであるということは ...
「デフォルトコンストラクタ」ですね。で、デフォルトコンストラクタが
trivial であるための条件についても上記のコピー・ムーブと同様に
仮想関数を持たないことなど追加の条件があります。
> 継承をしている場合、 ... 非staticなデータメンバーを持つこと
基底クラスすべてが非 static データメンバを持たない場合は、派生した
クラスが非 static データメンバを持ってもいいようです。
> 非staticなデータメンバーを持つ同じクラスを、複数継承しないこと。
これがどこから出てきたのかわかりませんが、ドラフトのとおりの列挙順なら
そこにある条件は、一番初めの非 static データメンバと同じ型の基底クラスを
持たないこと、となっています。
> memcpyでコピー出来るクラスの制限は、 ... 仮想関数があってもいい。
2点目として挙げたコピー・ムーブを trivial とするための条件に仮想関数も
仮想基底クラスも持たないことが含まれるので、そうはいかないようです。
has no base classes with non-static data membersの解釈を間違えました。
ReplyDeletetrivially copyable classのコンストラクタや代入演算子については、まあ、この程度の説明で、実用上問題ないかと思ったので、こう書きました。
trivially copyable classが仮想関数や仮想基本クラスを持てないというのは、どこに書いてあるのでしょうか。
同じく n3092 で記載箇所の確認をしています。
ReplyDeleteクラスが trivially copyable class となるための条件は 9 [class] p5 に
記載されていて、それによると non-trivial なムーブ・コピーコンストラクタ
および代入演算子を持たないことが必要となります。そして
ムーブ・コピーコンストラクタが trivial となる条件については
12.8 [class.copy] p13 に、ムーブ・コピー代入演算子については同じく
p27 に条件が記載されています。
うへ、これは気がつかなかった。
ReplyDelete>これまでPODに拘る理由というのは、memcpyなどで単純なバイト列のコピー出来るかどうかである。
ReplyDeleteいいえ、C言語と受け渡しするためです。
memcpyができることはその要件の一つに過ぎません。
CとC++の両方で矛盾なく扱えるためにはtrivialとstandard-layoutの両方が必要です。つまりPODです。
まあ、それもあるんですけどね。
ReplyDelete