namespace std { // Could use is_standard_layout && is_trivial instead of the builtin. template struct is_pod : public integral_constant { }; }
9 Answer
595
_POD_は_Plain Old Data_を表します。つまり、コンストラクタ、デストラクタ、仮想メンバ関数を持たないクラス(キーワード struct`またはキーワード
class`で定義されているかどうかにかかわらず)です。 http://en.wikipedia.org/wiki/Plain_Old_Data_Structures [PODに関するウィキペディアの記事]はもう少し詳しく説明し、次のように定義しています:
_ C ++のPlain Old Data Structureは、メンバーとしてPODSのみを含む集計クラスであり、ユーザー定義のデストラクタ、ユーザー定義のコピー代入演算子、およびメンバーへのポインタ型の非静的メンバーはありません。 _
詳細については、https://stackoverflow.com/a/4178176/734069 [C 98/03に対するこの回答]を参照してください。 C 11はPODを取り巻く規則を変更し、それらを大幅に緩和したので、https://stackoverflow.com/a/7189821/734069 [ここでフォローアップの回答を必要としています]。
307
PODは、(コンパイラを含む)Cコンパイラが構造内で「魔法」が起こらないことを保証する型です。たとえば、vtablesへの隠しポインタ、他の型にキャストされるときにアドレスに適用されるオフセットなどです。少なくともターゲットのPODもそうであれば)、コンストラクタ、またはデストラクタ。 おおまかに言って、型はその中の唯一のものが組み込み型とそれらの組み合わせであるときPODです。 結果はC型のように振舞うものです。
「int」、「char」、「wchar_t」、「bool」、「float」、「double」はPODです。
それらの long / short`および
signed / unsigned`バージョン。
ポインター(関数へのポインターとメンバーへのポインターを含む)は POD、
「列挙型」はPODです
const`または
volatile` PODはPODです。
PODの「クラス」、「構造」または「ユニオン」は、すべてが 非静的データメンバは「パブリック」であり、基本クラスもコンストラクタもデストラクタも仮想メソッドもありません。 静的メンバーは、この規則の下で何かがPODであることを止めません。 この規則はC 11で変更され、特定の非公開メンバーが許可されます:https://stackoverflow.com/questions/4762788/can-a-class-with-all-private-members-be-a-pod-class/4762944# 4762944 [すべてのプライベートメンバーを含むクラスをPODクラスにすることはできますか?]
ウィキペディアは、PODにタイプのメンバーを含めることはできないと言うのは間違っています メンバーへのポインター。 それどころか、それはC 98の言い回しには正しいのですが、TC1はメンバーへのポインタがPODであることを明示しました。
_ _ * 3.9(10):*「算術型(3.9.1)、列挙型、ポインター型、およびメンバー型へのポインター(3.9.2)およびこれらの型のcv修飾バージョン(3.9.3)は、集合的に呼び出し側スカラー型です。 スカラ型、POD構造体型、POD共用体型(9節)、そのような型の配列、およびこれらの型のcv修飾バージョン(3.9.3)をまとめてPOD型と呼びます。」
9(4):* "POD-structは、非POD-struct型、非POD-union型(またはそのような型の配列)、または参照型の非静的データ・メンバーを持たない集約クラスです。ユーザー定義のコピー演算子。ユーザー定義のデストラクタはありません。 同様に、POD共用体は、非POD構造体、非POD共用体(またはそのような型の配列)、または参照の非静的データ・メンバーを持たず、ユーザー定義のコピー演算子もなしも持たない集約共用体です。ユーザー定義デストラクタ。
8.5.1(1):*「集合体は、ユーザー宣言コンストラクタ(12.1)、プライベートまたは保護された非静的データメンバー(11節)、ベースクラス(節)を持たない配列またはクラス(9節)です。 10)仮想機能なし(10.3)。」 _ _
16
一言で言えば、それはすべての組み込みデータ型です。 「int」、「char」、「float」、「long」、「unsigned char」、「double」など)、およびすべてのPODデータの集約。 はい、それは再帰的な定義です。 ;)
より明確に言うと、PODは「構造体」と呼ばれるものです。つまり、単なるデータを格納するユニットまたはユニットのグループです。
10
私が理解しているように、POD(PlainOldData)は単なる生データです - それは必要ではありません:
建設される
破壊される
カスタム演算子があります。
仮想機能を持ってはいけません
演算子をオーバーライドしてはいけません。
is_pod`という構造体があります。
namespace std { // Could use is_standard_layout && is_trivial instead of the builtin. template struct is_pod : public integral_constant { }; }
(ヘッダーのtype_traitsから)
+ 参照:
8
POD(plain old data)オブジェクトは、これらのデータ型の1つ(基本型、ポインタ、共用体、構造体、配列、またはクラス)を持ち、コンストラクタはありません。 逆に、非PODオブジェクトはコンストラクタが存在するオブジェクトです。 PODオブジェクトは、そのタイプに適したサイズの記憶域を取得した時点で存続期間を開始し、その存続期間はオブジェクトの記憶域が再利用されるか割り当て解除されると終了します。
PlainOldData型には、次のものも含めないでください。
仮想機能(独自または継承)
仮想基本クラス(直接または間接)
PlainOldDataのよりゆるい定義は、コンストラクタを持つオブジェクトを含みます。しかし、仮想的なものを持つものは除外されます。 PlainOldData型に関する重要な問題は、それらが非多態性であるということです。 継承はPOD型で実行できますが、ImplementationInheritance(コードの再利用)に対してのみ実行し、多態性/サブタイプ化に対しては実行しないでください。
(厳密ではないが)一般的な定義は、PlainOldData型がVeeTableを持たないものなら何でもということです。
5
C 11からC 17までの `static_assert`とPOD効果を持つすべての非PODケースの例*
is_pod`はC 11で追加されたので、とりあえずその標準以降を考えましょう。
is_pod`はC 20から削除されます。置き換えがサポートされるようになったので、これを更新しましょう。
POD制限は標準が進化するにつれてますます緩和されてきました。私はifdefを通して例の中のすべての緩和をカバーすることを目指しています。
libstdcは、ほんの少しだけテストを行っています。https://github.com/gcc-mirror/gcc/blob/gcc-8_2_0-release/libstdc%2B%2B-v3/testsuite/20_util/is_pod/value.ccしかしそれだけです。少なすぎます。 メンテナ:この記事を読んだ場合はこれをマージしてください。 https://softwareengineering.stackexchange.com/questions/199708/is-there-a-compliance-test-for-c-compilersに記載されているすべてのC testsuiteプロジェクトをチェックアウトするのは怠惰です。
#include #include #include int main(){#if __cplusplus> = 201103L //#PODではない// // POD以外の例 cppreferenceのすべての非再帰的非POD分岐を見ていきましょう。 {//自明でないことは非PODを意味します。 // https://en.cppreference.com/w/cpp/named_req/TrivialType {// 1つ以上のデフォルトコンストラクタがあり、それらはすべて自明または削除されており、少なくとも1つは削除されていません。 {//独自のカスタムのデフォルト以外のコンストラクタを使用してデフォルトのコンストラクタを//削除したので、簡単ではありません。 {struct C {C(int){}}; static_assert(std :: is_trivially_copyable()、 ""); static_assert(!std :: is_trivial()、 ""); static_assert(!std :: is_pod()、 ""); } //いいえ、これもデフォルトの簡単なコンストラクタではありません。// https://en.cppreference.com/w/cpp/language/default_constructor // //コンストラクタはユーザー指定ではありません(つまり暗黙的に定義されています)または//最初の宣言でデフォルト設定){struct C {C(){}}; static_assert(std :: is_trivially_copyable()、 ""); static_assert(!std :: is_trivial()、 ""); static_assert(!std :: is_pod()、 ""); }} //簡単にコピーできないので、簡単ではありません。 {struct C {C(C //非標準レイアウトは非PODを意味します。 // https://en.cppreference.com/w/cpp/named_req/StandardLayoutType {//アクセス制御が異なる非静的メンバー。 {//私はパブリックであり、jはプライベートです。 {struct C {public:int i;} private:int j; ; static_assert(!std :: is_standard_layout()、 ""); static_assert(!std :: is_pod()、 ""); } //これらは同じアクセス制御を持ちます。 {struct C {private:int i;}; int j; ; static_assert(std :: is_standard_layout()、 ""); static_assert(std :: is_pod()、 ""); 構造体D {public:int i; int j; ; static_assert(std :: is_standard_layout()、 ""); static_assert(std :: is_pod()、 ""); }} //仮想機能。 {構造体C {仮想空隙f()= 0; ; static_assert(!std :: is_standard_layout()、 ""); static_assert(!std :: is_pod()、 ""); } //参照である非静的メンバー {struct C {int // // - //静的でないデータメンバーを持つ基本クラスがない、または// - 最も派生クラスにある静的でないデータメンバーを持たない//静的でないデータメンバーを持つ最大1つの基本クラス{//非PODは、非静的データメンバーを持つ2つの基本クラスがあるためです。 {struct Base1 {int i;} ; Base2 {int j; ;構造体C:Base1、Base2 {}。 static_assert(!std :: is_standard_layout()、 ""); static_assert(!std :: is_pod()、 ""); } // POD:非静的メンバを持つ基本クラスが1つだけあります。 {struct Base1 {int i;} ;構造体C:Base1 {}; static_assert(std :: is_standard_layout()、 ""); static_assert(std :: is_pod()、 ""); } //非静的メンバーを持つ1つの基本クラス:Base1、Base2には何もありません。 {struct Base1 {int i;} ; Base2 {}を構造化します。構造体C:Base1、Base2 {}。 static_assert(std :: is_standard_layout()、 ""); static_assert(std :: is_pod()、 ""); }} //最初の非静的データメンバーと同じ型の基本クラス // TODOがGCC 8.1に失敗する-std = c 11、14、および17。 {struct C {};構造体D:C {C c; ; // static_assert(!std :: is_standard_layout()、 ""); // static_assert(!std :: is_pod()、 ""); ; // C 14標準レイアウトの新しい規則 {//同じ型の2つの(おそらく間接的な)基本クラスサブオブジェクトがあります。 //ここでCは間接的に "Base"である2つの基底クラスを持ちます。 // // GCC 8.1でTODOが失敗する-std = c 11、14、および17。 //例はcppreferenceからコピーして貼り付けたものです。 {struct Q {}; struct S:Q {}; struct T:Q {}; struct U:S、T {}; //標準レイアウトクラスではない:Q型の2つの基本クラスサブオブジェクト// static_assert(!std :: is_standard_layout()、 ""); // static_assert(!std :: is_pod()、 ""); } //すべての非静的データメンバーとビットフィールドを同じクラスで//宣言します(すべて派生クラスまたはすべて基底クラス)。 {struct Base {int i;} ; struct Middle:Base {};構造体C:中{int j; ; static_assert(!std :: is_standard_layout()、 ""); static_assert(!std :: is_pod()、 ""); } //基本クラスのサブオブジェクトのどれも、最初の非静的データメンバーとして//非共用体型の//と同じ型を持ちません// // TODO:適切な例を作ることができなかったC 11のように、 //しかし再帰性が追加されています。 // TODOは、C 14ではPODであるがC 11ではPODではない例を考え出す。 }}} //#POD // // PODの例 POD以外の例にうまく収まらないものすべて。 {//これ以上のPODは得られません。 {struct C {}; static_assert(std :: is_pod()、 ""); static_assert(std :: is_pod()、 ""); } // PODの配列はPODです。 {struct C {}; static_assert(std :: is_pod()、 ""); static_assert(std :: is_pod()、 ""); } //非公開メンバー:C 11でPODになりました// https://stackoverflow.com/questions/4762788/can-a-class-with-all-private-members-be-a-pod-class/4762944#4762944 {構造体C {private:int i; ; #if __cplusplus> = 201103L static_assert(std :: is_pod()、 ""); #else static_assert(!std :: is_pod()、 ""); #endif} //ほとんどの標準ライブラリコンテナは、簡単ではないのでPODではありません。//これは、標準のインタフェース定義から直接見ることができます。 // https://stackoverflow.com/questions/27165436/pod-implications-for-a-struct-which-holds-an-standard-library-container {static_assert(!std :: is_pod>()、 "") ; static_assert(!std :: is_trivially_copyable>()、 ""); // https://stackoverflow.com/questions/3674247/is-stdarrayt-s-guaranteed-to-be-pod-if-t-is-pod static_assert(std :: is_pod>( )、 ""); }} //#POD効果// // PODnessにはどのような効果があるのかを確認しましょう。 // //失敗の多くは未定義の動作であるため、これを自動的に行うのは簡単ではありません。 // //良い初期のリストは以下にあります。// https://stackoverflow.com/questions/4178175/what-are-aggregates-and-pods-and-how-why-are-they-special/4178176 #4178176 {struct Pod {uint32_t i; uint64_t j; ; static_assert(std :: is_pod()、 ""); NotPod(NotPod(uint32_t i、uint64_t j)):i(i)、j(j){} uint32_t i; uint64_t j; ; static_assert(!std :: is_pod()、 ""); // __attribute __((packed))はPODに対してのみ機能し、POD以外に対しては無視され、警告を発します。// https://stackoverflow.com/questions/35152877/ignoring-packed-attribute-because-of-unpacked -non-pod-field / 52986680#52986680 {構造体C {int i; ; 構造体D:C {int j; ; 構造体E {D d; } / * __ attribute __((packed))* /; static_assert(std :: is_pod()、 ""); static_assert(!std :: is_pod()、 ""); static_assert(!std :: is_pod()、 ""); #endif}
https://github.com/cirosantilli/cpp-cheat/blob/eb1b019bde11b8556fbb959f990c5c8bf132a0a5 / cpp / pod.cpp [GitHub upstream]。
でテスト済み:
11 14 17の標準入力。 $ stdをエコーします。 g -8 -Wall -Werror -Wextra -pedantic -std = c $ std pod.cpp;終わった
Ubuntu 18.04、GCC 8.2.0上。
3
is_pod`はC 20では推奨されなくなります。 詳細はhttps://stackoverflow.com/questions/48225673/why-is-stdis-pod-deprecated-in-c20 [この]質問を参照してください。
1
_ PODと非PODをまったく区別する必要があるのはなぜですか? _
CはCの延長として生活を始めた。 現代のCはもはやCの厳密なスーパーセットではありませんが、人々は2つの間の高いレベルの互換性をまだ期待しています。
大まかに言って、PODタイプはCと互換性があるタイプであり、おそらく同様に重要なことには特定のABI最適化と互換性があります。
Cと互換性を保つためには、2つの制約を満たす必要があります。
レイアウトは対応するCタイプと同じでなければなりません。
型は、同じ方法で関数に渡され、関数から返される必要があります 対応するCタイプとして。
特定のC機能はこれと互換性がありません。
仮想メソッドは、仮想メソッドテーブルへの1つ以上のポインタを挿入することをコンパイラに要求します。これはCには存在しません。
ユーザー定義のコピーコンストラクタ、移動コンストラクタ、コピー代入、およびデストラクタは、パラメータの受け渡しに影響します。 多くのC ABIは小さなパラメータをレジスタに渡したり返したりしますが、ユーザ定義のコンストラクタ/割り当て/デストラクタに渡された参照はメモリの場所でのみ機能します。
したがって、どのタイプが「C互換」であることが期待できるのか、およびどのタイプが不可能であるのかを定義する必要があります。 C 03はこの点でやや厳しすぎました。 C 11はかなり物事を開いた。
-6
Cでは、Plain Old Dataは単にint、charなどのようなものが使われる唯一の型であるという意味ではありません。 Plain Old Dataは実際にはメモリ上のある場所から別の場所にmemcpy構造体を取ることができることを意味します。 爆破しないでください)。 あなたのクラス、あるいはあなたのクラスが含んでいるクラスがメンバとしてポインタや参照、あるいは仮想関数を持つクラスを持っている場合、これは壊れます。 本質的には、もしポインタがどこかに関わっていなければならないなら、それはPlain Old Dataではありません。