C++0x POD再考

C++03 での POD の定義にはいくつか問題があります。


【厳格すぎる要件】
これは、未定義動作に依存する愚かな設計を行なうことをユーザーに強います。

たとえば、 std::pair 型の配列が2つある場合、 memcpy(A2, A1, sizeof(A2)) が安全だと期待するのが自然ですが、std::pair にはユーザー定義のコンストラクタがあるので集成体とは見なされず、 それは同時に POD とも見なされなくなるので、標準ではこれを未定義動作としています。
(でも、動いてしまうことがある)


【PODと集成体の結合】
POD の現在の定義は、集成体の定義に依存し、その結果いくつかの障害を引き起こします。

POD はかなりシンプルな型にオブジェクト表現保証、レイアウト互換性保証、メモリ連続保証およびメモリコピー能力保証を提供しますが、まだより複雑な型のためにコンパイラはそのような問題の多くの自由を残します。
集成体は、初期化子を使用した初期化を提供します。
それ以外は、この2つの概念は完全に直交です。
そのため、集成体から POD を定義することは混乱をもたらします。


【自明(trivial)な特殊メンバ関数の要件とレイアウト要件の結合】
標準は、自明(trivial)な構築、コピー、代入、破棄が唯一の要件である多くの場所で POD もしくは非 POD としての要件を記述します。
いくつかの場所では、 POD もしくは非 POD の要件はレイアウト要件から自明な特殊メンバ関数を分けることがよりきれいな仕様につながることを明示するために使用されます。



こういった問題点を解決するため、 C++0x では POD の定義が以下のように変更されます。


・POD は、新たな2つのカテゴリによって定義される; trival types と standard-layout types

・これらの型は集成体の定義に依存しない

・自明な特殊メンバ関数が使用可能な場合、POD と trival class はコンストラクタを持つことを許可する

・POD 、trivial types および standard-layout types は基本クラスを持つことを許可する
 ただし、基本クラスは仮想関数と仮想基本クラスを持つことを許可しない

・POD と standard-layout types は、アクセス制御(publicとか)を持つことを許可する
 ただし、全ての非静的データメンバには同じアクセス制御がなければならない



POD の仕様は以下のようになります。

・trival-class : 自明な特殊メンバ関数を持っているクラス


・standard-layout-class :
  ・非静的メンバは standard-layout-class のみ
  ・仮想関数、仮想基本クラスを持っていない
  ・全ての非静的データメンバが同じアクセス制御を持っている
  ・非 standard-layout-class の基本クラスを持っていない
  ・最派生クラスに非静的データメンバを持つ場合、基底クラスに非静的データメンバを持ってはいけない
  ・最初の非静的データメンバと同じ基本クラスを持たない


POD 型は、 trival-class かつ standard-layout-class で、非 POD もしくは参照の非静的データメンバを持たないクラスです。





※特殊メンバ関数:デフォルトコンストラクタ、コピーコンストラクタ、コピー代入演算子、デストラクタ
※自明(trival)な特殊メンバ関数:コンパイラが自動生成した特殊メンバ関数(Not ユーザー定義)



N2342 POD's Revisited; Resolving Core Issue 568 (Revision 5)

C++0x言語拡張まとめ