C ++のPODタイプとは何ですか?


978

私はこの用語PODタイプに数回遭遇しました。
どういう意味ですか?



5
承認された回答についての議論については、chat.stackoverflow.com / transcript / message / 213026213026および翌日のメッセージを参照してください
Johannes Schaub-litb


@ paxos1977:根本的に間違った答えがここで終わるグーグルを誤解させないように、「解決策」(現在はヒューギルの答え)の選択を変更してください。
乾杯とhth。-Alf

c)スタイルの文字列はPODタイプではないと結論付けました。1。)ポインターが文字列データに隣接していない、2。)文字列をPODタイプにするためには、タイプを確認する必要があります。 PODタイプの事前定義されたサイズ内にnil-term charが含まれていたため、未定義の動作が発生しました。

回答:


695

PODは、Plain Old Dataの略です。structつまり、classコンストラクター、デストラクター、および仮想メンバー関数のないクラス(キーワードまたはキーワードで定義されているかどうか)です。ウィキペディアのPODに関する記事では、もう少し詳しく説明し、次のように定義しています。

C ++のプレーンオールドデータ構造は、メンバーとしてPODSのみを含み、ユーザー定義のデストラクター、ユーザー定義のコピー代入演算子、およびポインターからメンバーへの型の非静的メンバーを持たない集約クラスです。

詳細については、C ++ 98/03のこの回答をご覧ください。C ++ 11はPODを取り巻く規則を変更し、それらを大幅に緩和したため、ここでフォローアップの回答必要となりました


35
違いがあります。組み込み型は、「組み込みの」言語プリミティブです。PODタイプは、これらに加えて、これら(およびその他のPOD)の集約です。
アダムライト

59
PODタイプには、非PODタイプにはない特性があります。たとえば、グローバルなconst、PODタイプの構造体がある場合、中括弧表記でその内容を初期化できます。それは読み取り専用メモリに入れられ、初期化するためにコードを生成する必要はありません(コンストラクターなど)。それはプログラムイメージの一部だからです。これは、RAM、ROM、またはフラッシュに厳しい制約があることが多い組み込みユーザーにとって重要です。
Mike DeSimone

35
C ++ 11では、std :: is_pod <MyType>()を実行して、MyTypeがPODかどうかを確認できます。
allyourcode 2014年

7
Bjarne StroustrupのC ++パフォーマンスに関するテクニカルレポートでは、C ++標準はPODを「レイアウト、初期化、およびmemcpyでコピーできるCの同等のデータ型と互換性のあるデータ型」と説明していると述べています。おそらく、PODタイプとPOD構造を区別する必要があります。
user34660 2015年

6
-1この回答は2016年8月16日現在でも根本的に間違っており、誤解を招く可能性があります。PODタイプはクラスタイプに限定されていません。
乾杯とhth。-Alf

353

非常に非公式:

PODはタイプ(クラスを含む)であり、C ++コンパイラは構造内で「マジック」が発生しないことを保証します。たとえば、vtableへの隠しポインタ、他のタイプにキャストされたときにアドレスに適用されるオフセット(少なくとも、ターゲットのPODも)、コンストラクタ、またはデストラクタ。大まかに言えば、その中にある唯一のものが組み込み型とそれらの組み合わせである場合、型はPODです。結果は、Cタイプのように「振る舞う」ものです。

非公式ではない:

  • intcharwchar_tboolfloatdoubleなどあり、PODをしているlong/shortsigned/unsigned、それらのバージョン。
  • ポインター(関数へのポインターとメンバーへのポインターを含む)はPODです。
  • enums PODです
  • constまたはvolatilePODは、PODです。
  • classstruct又はunion鞘のPODは、すべての非静的データメンバーであることが提供されるpublic、そしてそれは、ベースクラスなしコンストラクタ、デストラクタ、または仮想メソッドを持っていません。静的メンバーは、このルールの下で何かがPODであることを止めません。このルールはC ++ 11で変更され、特定のプライベートメンバーが許可されています。すべてのプライベートメンバーを持つクラスをPODクラスにすることはできますか?
  • ウィキペディアは、PODがタイプポインターへのメンバーのメンバーを持つことができないと言うのは間違っています。むしろ、それはC ++ 98の言い回しでは正しいのですが、TC1は、メンバーへのポインターがPODであることを明示しました。

正式に(C ++ 03標準):

3.9(10):「算術型(3.9.1)、列挙型、ポインター型、メンバー型へのポインター(3.9.2)、およびこれらの型のcv修飾バージョン(3.9.3)は、集合的に呼び出し元のスカラー型です。スカラータイプ、POD構造体タイプ、PODユニオンタイプ(9節)、そのようなタイプの配列、およびこれらのタイプのcv修飾バージョン(3.9.3)は、まとめてPODタイプと呼ばれます。

9(4):「POD構造体は、非POD構造体型、非PODユニオン型(またはそのような型の配列)または参照型の非静的データメンバーを持たない集計クラスであり、ユーザーコピー演算子を定義し、ユーザー定義のデストラクタはありません。同様に、PODユニオンは、非POD構造、非PODユニオン(またはそのようなタイプの配列)、または参照の非静的データメンバーを持たない集約ユニオンです。また、ユーザー定義のコピー演算子とユーザー定義のデストラクタはありません。

8.5.1(1):「集約は配列またはクラス(9節)であり、ユーザー宣言コンストラクター(12.1)、プライベートまたは保護された非静的データメンバー(11節)、基本クラス(10節)はありません。仮想機能はありません(10.3)。」


3
フォーマル/フォーマルが少ない。経験則を追加できます。組み込み型および組み込み型の集約(またはそのようなもの)。正確な定義を得るために、知識を使いやすくする必要があります。
マーティンヨーク

1
" cast_to another type when when offsets to another type"ビットは少し間違っています。これらのオフセットは、基本クラスまたは派生クラスにキャストするときに適用されます。したがって、POD基本クラスポインターから非POD派生クラスにキャストした場合でも、調整が発生する可能性があります。
MSalters 2008

1
@Steve Jessop:PODと非PODをまったく区別する必要があるのはなぜですか?
Lazer

6
@Lazer:「PODはどのように動作するのですか?」「PODの意味」とは対照的に。要約すると、違いは初期化(したがってmemcpyを使用してオブジェクトを複製する)、そのコンパイラーのC構造体レイアウトとの互換性、およびポインターのアップキャストとダウンキャストに関連しています。PODは「Cタイプのように動作する」が、POD以外の動作は保証されていません。したがって、型をC構造体のように移植可能に動作させたい場合は、それがPODであることを確認する必要があるため、違いを知る必要があります。
Steve Jessop

4
@muntoo:本当に、私はウィキペディアからの古い情報を引用する答えにコメントしていました。私はその答えを編集できたと思いますが、私の考えに同意するために他の人の答えを編集して周りに行くと、私がどれほど正しいと思っていても、問題のにおいがします。
スティーブジェソップ

21

プレーンな古いデータ

要するに、それはすべてのデータ型(例えば、内蔵されたintcharfloatlongunsigned chardouble、など)とPODデータをすべて集約。はい、それは再帰的な定義です。;)

より明確にするために、PODは「構造体」と呼ばれるものです。データを格納するだけのユニットまたはユニットのグループです。


13
それらを「構造体」と呼ぶこともあるのは事実です。ただし、構造体は必ずしもPODタイプではないため、そうすることは常に間違っています。
スティーブジェソップ

7
明らかに...構造体とクラスはほぼ同等ですが、「ビジネス」では、「構造体」を通常はctorとdtorなしで、通常は値のセマンティクスを持つ単純なデータコレクターと呼びます...
ugasoft

2
私にとって、structをclassキーワードと同じにするか、またはそれに近くするのはC ++の誤りでした。structは、クラスへのパブリックデフォルトアクセスのみを追加します。Cのような構造体を作る方が簡単で、c ++の0日目にPODがあったはずです。
user1708042

ugasoft:あなたの答えは誤解を招くかもしれません-あなたのコメントはそれが標準ではなく実際にそのように使用されている欠けている詳細を説明しました おっと、8年、あなたはここにいますか?;-)
hauron 2016年

文字列を除いて、最初に文字列の長さを決定せずにmemcpyでそれをコピーすることはできません。

12

私が理解しているように、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から)


参照:


2
不正解です。PODタイプには、メンバー関数またはオーバーロードされた演算子がある場合があります。(ただし、仮想メンバー関数がない場合があります。)
コリンDベネット

@ColinDBennettうん、そうだね。混乱させて申し訳ありません。アンサーの内外で編集されました。
набиячлэвэли

10

POD(プレーンオールドデータ)オブジェクトは、これらのデータ型の1つ(基本型、ポインター、共用体、構造体、配列、またはクラス)を持ち、コンストラクターはありません。逆に、非PODオブジェクトは、コンストラクターが存在するオブジェクトです。PODオブジェクトは、そのタイプに適したサイズのストレージを取得するとライフタイムを開始し、オブジェクトのストレージが再利用または割り当て解除されたときに終了します。

また、PlainOldData型には、次のものを含めることはできません。

  • 仮想機能(独自の機能または継承された機能)
  • 仮想基本クラス(直接または間接)。

PlainOldDataの緩い定義には、コンストラクターを持つオブジェクトが含まれます。ただし、仮想的なものはすべて除外されます。PlainOldDataタイプの重要な問題は、それらが非多態性であることです。継承はPODタイプで行うことができますが、実装形態継承(コードの再利用)に対してのみ行う必要があり、ポリモーフィズム/サブタイピングでは行わないでください。

一般的な(厳密には正しくありませんが)定義は、PlainOldData型はVeeTableを持たないものです。


Yuorの回答は非常に良いですが、この質問は8年前の回答に加えて、他のいくつかの良い回答を受け入れています。まだ回答されていない質問に答えるために知識を使用している場合は、SOにさらに貢献できます)))
mvidelgauz

10

PODと非PODをまったく区別する必要があるのはなぜですか?

C ++はCの拡張として生まれました。現在のC ++はもはやCの厳密なスーパーセットではありませんが、人々はまだ2つの間の高いレベルの互換性を期待しています。

大まかに言えば、POD型はCと互換性があり、おそらく同じくらい重要なことに、特定のABI最適化と互換性がある型です。

Cと互換性を持たせるには、2つの制約を満たす必要があります。

  1. レイアウトは、対応するCタイプと同じでなければなりません。
  2. 型は、対応するCの型と同じ方法で関数に渡され、関数から返される必要があります。

特定のC ++機能はこれと互換性がありません。

仮想メソッドを使用するには、コンパイラーが仮想メソッドテーブルへのポインターを1つ以上挿入する必要があります。これはCには存在しないものです。

ユーザー定義のコピーコンストラクター、移動コンストラクター、コピーの割り当て、およびデストラクタは、パラメーターの受け渡しと戻りに影響を与えます。多くのC ABIはレジスタに小さなパラメータを渡して返しますが、ユーザー定義のコンストラクタ/割り当て/デストラクタに渡される参照は、メモリロケーションでのみ機能します。

したがって、「C互換」であると期待できる型とできない型を定義する必要があります。C ++ 03はこの点でいくらか厳格でした。ユーザー定義のコンストラクターは組み込みコンストラクターを無効にし、それらを追加しようとすると、ユーザー定義になり、タイプが非ポッドになります。C ++ 11は、ユーザーが組み込みのコンストラクターを再導入できるようにすることで、物事をかなり開きました。


8

static_assertC ++ 11からC ++ 17までのすべての非PODケースとPOD効果の例

std::is_pod C ++ 11で追加されたので、とりあえずその標準以降について考えてみましょう。

std::is_podhttps://stackoverflow.com/a/48435532/895245で言及されているように、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でテストを行っていますが、少なすぎる。メンテナ:この投稿を読んだら、これをマージしてください。/software/199708/is-there-a-compliance-test-for-c-compilersで言及されているすべてのC ++テストスイートプロジェクトをチェックするのは面倒です

#include <type_traits>
#include <array>
#include <vector>

int main() {
#if __cplusplus >= 201103L
    // # Not POD
    //
    // Non-POD examples. Let's just walk all non-recursive non-POD branches of cppreference.
    {
        // Non-trivial implies non-POD.
        // https://en.cppreference.com/w/cpp/named_req/TrivialType
        {
            // Has one or more default constructors, all of which are either
            // trivial or deleted, and at least one of which is not deleted.
            {
                // Not trivial because we removed the default constructor
                // by using our own custom non-default constructor.
                {
                    struct C {
                        C(int) {}
                    };
                    static_assert(std::is_trivially_copyable<C>(), "");
                    static_assert(!std::is_trivial<C>(), "");
                    static_assert(!std::is_pod<C>(), "");
                }

                // No, this is not a default trivial constructor either:
                // https://en.cppreference.com/w/cpp/language/default_constructor
                //
                // The constructor is not user-provided (i.e., is implicitly-defined or
                // defaulted on its first declaration)
                {
                    struct C {
                        C() {}
                    };
                    static_assert(std::is_trivially_copyable<C>(), "");
                    static_assert(!std::is_trivial<C>(), "");
                    static_assert(!std::is_pod<C>(), "");
                }
            }

            // Not trivial because not trivially copyable.
            {
                struct C {
                    C(C&) {}
                };
                static_assert(!std::is_trivially_copyable<C>(), "");
                static_assert(!std::is_trivial<C>(), "");
                static_assert(!std::is_pod<C>(), "");
            }
        }

        // Non-standard layout implies non-POD.
        // https://en.cppreference.com/w/cpp/named_req/StandardLayoutType
        {
            // Non static members with different access control.
            {
                // i is public and j is private.
                {
                    struct C {
                        public:
                            int i;
                        private:
                            int j;
                    };
                    static_assert(!std::is_standard_layout<C>(), "");
                    static_assert(!std::is_pod<C>(), "");
                }

                // These have the same access control.
                {
                    struct C {
                        private:
                            int i;
                            int j;
                    };
                    static_assert(std::is_standard_layout<C>(), "");
                    static_assert(std::is_pod<C>(), "");

                    struct D {
                        public:
                            int i;
                            int j;
                    };
                    static_assert(std::is_standard_layout<D>(), "");
                    static_assert(std::is_pod<D>(), "");
                }
            }

            // Virtual function.
            {
                struct C {
                    virtual void f() = 0;
                };
                static_assert(!std::is_standard_layout<C>(), "");
                static_assert(!std::is_pod<C>(), "");
            }

            // Non-static member that is reference.
            {
                struct C {
                    int &i;
                };
                static_assert(!std::is_standard_layout<C>(), "");
                static_assert(!std::is_pod<C>(), "");
            }

            // Neither:
            //
            // - has no base classes with non-static data members, or
            // - has no non-static data members in the most derived class
            //   and at most one base class with non-static data members
            {
                // Non POD because has two base classes with non-static data members.
                {
                    struct Base1 {
                        int i;
                    };
                    struct Base2 {
                        int j;
                    };
                    struct C : Base1, Base2 {};
                    static_assert(!std::is_standard_layout<C>(), "");
                    static_assert(!std::is_pod<C>(), "");
                }

                // POD: has just one base class with non-static member.
                {
                    struct Base1 {
                        int i;
                    };
                    struct C : Base1 {};
                    static_assert(std::is_standard_layout<C>(), "");
                    static_assert(std::is_pod<C>(), "");
                }

                // Just one base class with non-static member: Base1, Base2 has none.
                {
                    struct Base1 {
                        int i;
                    };
                    struct Base2 {};
                    struct C : Base1, Base2 {};
                    static_assert(std::is_standard_layout<C>(), "");
                    static_assert(std::is_pod<C>(), "");
                }
            }

            // Base classes of the same type as the first non-static data member.
            // TODO failing on GCC 8.1 -std=c++11, 14 and 17.
            {
                struct C {};
                struct D : C {
                    C c;
                };
                //static_assert(!std::is_standard_layout<C>(), "");
                //static_assert(!std::is_pod<C>(), "");
            };

            // C++14 standard layout new rules, yay!
            {
                // Has two (possibly indirect) base class subobjects of the same type.
                // Here C has two base classes which are indirectly "Base".
                //
                // TODO failing on GCC 8.1 -std=c++11, 14 and 17.
                // even though the example was copy pasted from cppreference.
                {
                    struct Q {};
                    struct S : Q { };
                    struct T : Q { };
                    struct U : S, T { };  // not a standard-layout class: two base class subobjects of type Q
                    //static_assert(!std::is_standard_layout<U>(), "");
                    //static_assert(!std::is_pod<U>(), "");
                }

                // Has all non-static data members and bit-fields declared in the same class
                // (either all in the derived or all in some base).
                {
                    struct Base { int i; };
                    struct Middle : Base {};
                    struct C : Middle { int j; };
                    static_assert(!std::is_standard_layout<C>(), "");
                    static_assert(!std::is_pod<C>(), "");
                }

                // None of the base class subobjects has the same type as
                // for non-union types, as the first non-static data member
                //
                // TODO: similar to the C++11 for which we could not make a proper example,
                // but with recursivity added.

                // TODO come up with an example that is POD in C++14 but not in C++11.
            }
        }
    }

    // # POD
    //
    // POD examples. Everything that does not fall neatly in the non-POD examples.
    {
        // Can't get more POD than this.
        {
            struct C {};
            static_assert(std::is_pod<C>(), "");
            static_assert(std::is_pod<int>(), "");
        }

        // Array of POD is POD.
        {
            struct C {};
            static_assert(std::is_pod<C>(), "");
            static_assert(std::is_pod<C[]>(), "");
        }

        // Private member: became POD in C++11
        // /programming/4762788/can-a-class-with-all-private-members-be-a-pod-class/4762944#4762944
        {
            struct C {
                private:
                    int i;
            };
#if __cplusplus >= 201103L
            static_assert(std::is_pod<C>(), "");
#else
            static_assert(!std::is_pod<C>(), "");
#endif
        }

        // Most standard library containers are not POD because they are not trivial,
        // which can be seen directly from their interface definition in the standard.
        // /programming/27165436/pod-implications-for-a-struct-which-holds-an-standard-library-container
        {
            static_assert(!std::is_pod<std::vector<int>>(), "");
            static_assert(!std::is_trivially_copyable<std::vector<int>>(), "");
            // Some might be though:
            // /programming/3674247/is-stdarrayt-s-guaranteed-to-be-pod-if-t-is-pod
            static_assert(std::is_pod<std::array<int, 1>>(), "");
        }
    }

    // # POD effects
    //
    // Now let's verify what effects does PODness have.
    //
    // Note that this is not easy to do automatically, since many of the
    // failures are undefined behaviour.
    //
    // A good initial list can be found at:
    // /programming/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<Pod>(), "");

        struct NotPod {
            NotPod(uint32_t i, uint64_t j) : i(i), j(j) {}
            uint32_t i;
            uint64_t j;
        };
        static_assert(!std::is_pod<NotPod>(), "");

        // __attribute__((packed)) only works for POD, and is ignored for non-POD, and emits a warning
        // /programming/35152877/ignoring-packed-attribute-because-of-unpacked-non-pod-field/52986680#52986680
        {
            struct C {
                int i;
            };

            struct D : C {
                int j;
            };

            struct E {
                D d;
            } /*__attribute__((packed))*/;

            static_assert(std::is_pod<C>(), "");
            static_assert(!std::is_pod<D>(), "");
            static_assert(!std::is_pod<E>(), "");
        }
    }
#endif
}

GitHubアップストリーム

テスト済み:

for std in 11 14 17; do echo $std; g++-8 -Wall -Werror -Wextra -pedantic -std=c++$std pod.cpp; done

Ubuntu 18.04、GCC 8.2.0。



-7

C ++では、Plain Old Dataは、int、charなどが使用される唯一のタイプであることを意味するだけではありません。プレーンオールドデータとは、実際には、メモリ内のある場所から別の場所にstruct memcpyを取得でき、期待どおりに動作する(つまり、爆発しない)ことを意味します。これは、クラス、またはクラスに含まれているクラスが、ポインターまたは参照であるメンバーとして、あるいは仮想関数を持つクラスとして持っている場合に機能しなくなります。基本的に、ポインタがどこかに含まれる必要がある場合、それは単純な古いデータではありません。


6
ポインターはPOD構造体で使用できます。参照はそうではありません。
j_random_hacker 2009

1
ここに不在者がいません。
icbytes 2014
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.