私は、POD タイプという用語に何度か遭遇しました。
どういう意味ですか?
9 に答える
PODはPlain Old Dataの略です。つまり、コンストラクタ、デストラクタ、および仮想メンバー関数を持たないクラス (キーワードstruct
またはキーワードで定義されているかどうかにかかわらず) です。POD に関するウィキペディアの記事では、もう少し詳しく説明し、次のように定義しています。class
C++ の Plain Old Data Structure は、メンバーとして PODS のみを含み、ユーザー定義のデストラクター、ユーザー定義のコピー代入演算子、およびポインターからメンバーへの型の非静的メンバーを持たない集約クラスです。
詳細については、この回答 for C++98/03 を参照してください。C++11 は POD を取り巻く規則を変更し、大幅に緩和したため、ここでフォローアップの回答が必要になりました。
非常に非公式:
PODは、C ++コンパイラが構造内で「魔法」が発生しないことを保証するタイプ(クラスを含む)です。たとえば、vtablesへの非表示のポインタ、他のタイプにキャストされたときにアドレスに適用されるオフセット(少なくともターゲットのPODの場合も)、コンストラクター、またはデストラクタ。大まかに言えば、タイプは、その中の唯一のものが組み込みタイプとそれらの組み合わせである場合、PODです。結果は、Cタイプの「ように機能する」ものになります。
非公式ではない:
int
、、、、、、はPODでありchar
、wchar_t
そのバージョンも同様です。bool
float
double
long/short
signed/unsigned
- ポインター(関数へのポインターおよびメンバーへのポインターを含む)はPODであり、
enums
PODですconst
またはvolatile
PODはPODです。- 、またはのPODは、すべての非静的データメンバーが
class
であり、基本クラスがなく、コンストラクタ、デストラクタ、または仮想メソッドがない場合のPODです。静的メンバーは、このルールの下で何かがPODであることを停止しません。このルールはC++11で変更され、特定のプライベートメンバーが許可されます。すべてのプライベートメンバーを持つクラスをPODクラスにすることはできますか?struct
union
public
- ウィキペディアは、PODがメンバーへのポインター型のメンバーを持つことはできないと言っているのは誤りです。むしろ、C ++ 98の表現は正しいのですが、TC1は、メンバーへのポインターがPODであることを明示しました。
正式に(C ++ 03標準):
3.9(10): "算術型(3.9.1)、列挙型、ポインター型、およびメンバー型へのポインター(3.9.2)と、これらの型のcv修飾バージョン(3.9.3)は、まとめて呼び出し元のスカラー型です。スカラータイプ、POD-structタイプ、POD-unionタイプ(9節)、そのようなタイプの配列、およびこれらのタイプのcv修飾バージョン(3.9.3)は、まとめてPODタイプと呼ばれます。
9(4):「POD-structは、タイプnon-POD-struct、non-POD-union(またはそのようなタイプの配列)または参照の非静的データメンバーを持たず、user-を持たない集約クラスです。コピー演算子を定義し、ユーザー定義のデストラクタはありません。同様に、POD-unionは、タイプnon-POD-struct、non-POD-union(またはそのようなタイプの配列)または参照の非静的データメンバーを持たない集約ユニオンです。また、ユーザー定義のコピー演算子やユーザー定義のデストラクタはありません。
8.5.1(1):「アグリゲートは配列またはクラス(9節)であり、ユーザーが宣言したコンストラクター(12.1)、プライベートまたは保護された非静的データメンバー(11節)、基本クラス(10節)はありません。仮想関数はありません(10.3)。」
つまり、すべての組み込みデータ型 (例: int
、char
、float
、long
、unsigned char
などdouble
) と POD データのすべての集約です。はい、再帰的な定義です。;)
より明確にするために、POD は私たちが「構造体」と呼んでいるものです: データを格納するだけのユニットまたはユニットのグループです。
POD と非 POD をまったく区別する必要があるのはなぜですか?
C++ は C の拡張として誕生しました。最新の C++ はもはや C の厳密なスーパーセットではありませんが、人々は依然として 2 つの間の高度な互換性を期待しています。プラットフォームの「C ABI」は、プラットフォーム上の他の言語の事実上の標準言語間 ABI としても頻繁に機能します。
大まかに言えば、POD 型は C と互換性のある型であり、おそらく同様に重要なことに、特定の ABI 最適化と互換性があります。
C と互換性を持たせるには、2 つの制約を満たす必要があります。
- レイアウトは、対応する C タイプと同じでなければなりません。
- 型は、対応する C 型と同じ方法で関数に渡され、関数から返される必要があります。
一部の C++ 機能は、これと互換性がありません。
仮想メソッドでは、コンパイラが仮想メソッド テーブルに 1 つ以上のポインターを挿入する必要がありますが、これは C には存在しません。
ユーザー定義のコピー コンストラクター、ムーブ コンストラクター、コピー代入、およびデストラクターは、パラメーターの受け渡しに影響します。多くの C ABI は小さなパラメーターをレジスターで渡したり返したりしますが、ユーザー定義のコンストラクター/代入/デストラクタに渡される参照はメモリ位置でしか機能しません。
そのため、「C 互換」であることが期待できる型とそうでない型を定義する必要があります。C++03 は、この点に関してやや厳格すぎました。ユーザー定義のコンストラクターは組み込みコンストラクターを無効にし、それらを再度追加しようとすると、ユーザー定義になり、型が非ポッドになります。C++11 では、ユーザーが組み込みのコンストラクターを再導入できるようにすることで、物事がかなり開かれました。
私が理解しているように、POD(PlainOldData)は単なる生データです-必要ありません:
- 構築される、
- 破壊され、
- カスタム演算子を使用します。
- 仮想機能があってはなりません。
- 演算子をオーバーライドしてはなりません。
何かがPODかどうかを確認する方法は? そのための構造体があり、次のように呼ばれstd::is_pod
ます。
namespace std {
// Could use is_standard_layout && is_trivial instead of the builtin.
template<typename _Tp>
struct is_pod
: public integral_constant<bool, __is_pod(_Tp)>
{ };
}
(ヘッダ type_traits より)
参照:
POD (plain old data) オブジェクトには、これらのデータ型 (基本型、ポインター、共用体、構造体、配列、またはクラス) のいずれかがあり、コンストラクターはありません。逆に、非 POD オブジェクトは、コンストラクターが存在するオブジェクトです。POD オブジェクトは、その型に適切なサイズのストレージを取得したときにその有効期間が開始し、オブジェクトのストレージが再利用または割り当て解除されたときにその有効期間が終了します。
PlainOldData 型には、次のいずれも含めてはなりません。
- 仮想関数 (独自または継承)
- 仮想基本クラス (直接または間接)。
PlainOldData のより緩やかな定義には、コンストラクタを持つオブジェクトが含まれます。ただし、仮想的なものは除きます。PlainOldData 型の重要な問題は、非多態的であることです。継承は POD 型で行うことができますが、実装継承 (コードの再利用) に対してのみ行うべきであり、ポリモーフィズム/サブタイピングに対しては行うべきではありません。
一般的な (ただし厳密には正しくない) 定義は、PlainOldData 型は VeeTable を持たないものであるというものです。
C++ では、Plain Old Data は単に int や char などの型だけが使用されるという意味ではありません。Plain Old Data とは実際には、構造体 memcpy をメモリ内のある場所から別の場所に移動できることを意味し、物事は期待どおりに機能します (つまり、爆発しない)。これは、クラス、またはクラスに含まれるクラスが、ポインターまたは参照であるメンバーとして、または仮想関数を持つクラスを持っている場合に壊れます。本質的に、ポインターがどこかに関与する必要がある場合、それは Plain Old Data ではありません。