2010-06-09

C++0xにおけるPODの定義

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なデータメンバーをもっていても構わない。アクセス指定もできる。

6 comments:

Anonymous said...

いくつか間違いと思われる記述が見られたので、 n3092 と照らし合わせ
ながらの突っ込みを入れておきます。

> 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 とするための条件に仮想関数も
仮想基底クラスも持たないことが含まれるので、そうはいかないようです。

江添亮 said...

has no base classes with non-static data membersの解釈を間違えました。
trivially copyable classのコンストラクタや代入演算子については、まあ、この程度の説明で、実用上問題ないかと思ったので、こう書きました。

trivially copyable classが仮想関数や仮想基本クラスを持てないというのは、どこに書いてあるのでしょうか。

Anonymous said...

同じく n3092 で記載箇所の確認をしています。

クラスが trivially copyable class となるための条件は 9 [class] p5 に
記載されていて、それによると non-trivial なムーブ・コピーコンストラクタ
および代入演算子を持たないことが必要となります。そして
ムーブ・コピーコンストラクタが trivial となる条件については
12.8 [class.copy] p13 に、ムーブ・コピー代入演算子については同じく
p27 に条件が記載されています。

江添亮 said...

うへ、これは気がつかなかった。

Anonymous said...

>これまでPODに拘る理由というのは、memcpyなどで単純なバイト列のコピー出来るかどうかである。
いいえ、C言語と受け渡しするためです。
memcpyができることはその要件の一つに過ぎません。
CとC++の両方で矛盾なく扱えるためにはtrivialとstandard-layoutの両方が必要です。つまりPODです。

江添亮 said...

まあ、それもあるんですけどね。