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:

  1. いくつか間違いと思われる記述が見られたので、 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 とするための条件に仮想関数も
    仮想基底クラスも持たないことが含まれるので、そうはいかないようです。

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

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

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

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

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

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

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

    ReplyDelete

You can use some HTML elements, such as <b>, <i>, <a>, also, some characters need to be entity referenced such as <, > and & Your comment may need to be confirmed by blog author. Your comment will be published under GFDL 1.3 or later license with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.