Question

J'ai rencontré ce terme de type POD à quelques reprises. Qu'est-ce que ça veut dire?

Était-ce utile?

La solution

POD signifie Plain Old Data - c’est-à-dire une classe (qu’elle soit définie avec le mot-clé struct ou le mot-clé class ) sans constructeurs, destructeurs et fonctions de membres virtuels. L'article de Wikipedia sur le POD est plus détaillé et le définit comme suit:

  

Une ancienne structure de données standard en C ++ est une classe agrégée qui ne contient que PODS en tant que membres, ne possède aucun destructeur défini par l'utilisateur, aucun opérateur d'affectation de copie défini par l'utilisateur et aucun membre non statique de type pointeur sur membre.

Vous trouverez plus de détails dans cette réponse pour C ++ 98/03 . C ++ 11 a modifié les règles entourant le POD, en les assouplissant considérablement. nécessitant une réponse de suivi ici .

Autres conseils

De manière très informelle:

Un POD est un type (y compris les classes) dans lequel le compilateur C ++ garantit qu’il n’y aura pas de "magique". passe dans la structure: par exemple, des pointeurs cachés vers vtables, des décalages qui sont appliqués à l'adresse lorsqu'elle est convertie en d'autres types (au moins si le POD de la cible aussi), des constructeurs ou des destructeurs. Grosso modo, un type est un POD lorsque ses seuls éléments sont des types intégrés et des combinaisons de ceux-ci. Le résultat est quelque chose qui "agit comme". un type C.

Moins informellement:

  • int , char , wchar_t , bool , float , double sont des POD, de même que les versions long / court et signés / non signés .
  • les pointeurs (y compris pointeur vers fonction et pointeur vers membre) sont des POD,
  • Les
  • enums sont des POD
  • un POD const ou volatile est un POD.
  • une classe , struct ou union de POD est un POD à condition que tous les membres de données non statiques soient public , et il n'a pas de classe de base et pas de constructeur, destructeur ou méthode virtuelle. Les membres statiques n'arrêtent pas que quelque chose soit un POD en vertu de cette règle Cette règle a changé dans C ++ 11 et certains membres privés sont autorisés: Une classe avec tous les membres privés peut-elle être une classe POD?
  • Wikipedia a tort de dire qu'un POD ne peut pas avoir de membres de type pointeur à membre. Ou plutôt, c'est correct pour le libellé C ++ 98, mais TC1 a expliqué explicitement que les pointeurs sur membre sont des POD.

Formellement (norme C ++ 03):

  

3.9 (10): "Des types arithmétiques (3.9.1), types d'énumération, types de pointeur et pointeur sur les types de membre (3.9.2) et les versions cv de ces types ( 3.9.3) sont collectivement des types scalaires d’appelant. Les types scalaires, les types de structure POD, les types d'union POD (article 9), les tableaux de ce type et les versions cv de ces types (3.9.3) sont collectivement appelés types POD "

".      

9 (4): "Une structure POD est une classe d'agrégat qui ne possède pas de données membres non statiques de type non-POD-struct, non-POD-union (ou tableau de tels types) ou référence, et n’a pas d’opérateur de copie défini par l’utilisateur ni de destructeur défini par l’utilisateur. De même, une union POD est une union agrégée qui ne possède pas de données membres non statiques de type union non POD, ni union POD (ni tableau de ce type), ni de référence, et ne comporte ni opérateur de copie défini par l'utilisateur ni opérateur. destructeur défini par l'utilisateur.

     

8.5.1 (1): "Un agrégat est un tableau ou une classe (clause 9) sans constructeurs déclarés par l'utilisateur (12.1), ni membres de données privés ou statiques protégés ( clause 11), pas de classes de base (clause 10) et pas de fonctions virtuelles (10.3). "

Données anciennes simples

En bref, ce sont tous les types de données intégrés (par exemple, int , char , float , long , caractère non signé , double , etc.) et toute l’agrégation de données POD. Oui, c'est une définition récursive. ;)

Pour être plus clair, un POD est ce que nous appelons une "structure": une unité ou un groupe d’unités qui ne font que stocker des données.

Si je comprends bien, le POD (PlainOldData) est simplement une donnée brute - il n’est pas nécessaire:

  • à construire,
  • être détruit,
  • avoir des opérateurs personnalisés.
  • Ne doit pas avoir de fonctions virtuelles,
  • et ne doit pas remplacer les opérateurs.

Comment vérifier si quelque chose est un POD? Eh bien, il existe une structure appelée 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)>
  { };
}

(à partir de l'en-tête type_traits)


Référence:

Un objet POD (plain old data) possède l’un de ces types de données - type fondamental, pointeur, union, structure, tableau ou classe - sans constructeur. Inversement, un objet non-POD est un objet pour lequel il existe un constructeur. Un objet POD commence sa vie lorsqu'il obtient un stockage de la taille appropriée pour son type et sa fin de vie prend fin lorsque le stockage de l'objet est soit réutilisé, soit libéré. ??

Les types PlainOldData ne doivent pas non plus avoir l'un des éléments suivants:

  • Fonctions virtuelles (soit les leurs, soit héritées)
  • Classes de base virtuelles (directes ou indirectes).

Une définition plus souple de PlainOldData inclut des objets avec des constructeurs; mais exclut ceux qui ont quelque chose de virtuel. Le problème important des types PlainOldData est qu’ils ne sont pas polymorphes. L'héritage peut être fait avec les types POD, mais ne devrait l'être que pour ImplementationInheritance (réutilisation du code) et non pour le polymorphisme / sous-typage.

Une définition courante (bien que non strictement correcte) est qu'un type PlainOldData est tout ce qui n'a pas de VeeTable.

Exemples de tous les cas autres que POD avec static_assert de C ++ 11 à C ++ 17 et effets POD

std :: is_pod a été ajouté en C ++ 11, considérons donc cette norme pour le moment.

std :: is_pod sera supprimé de C ++ 20, comme indiqué à l'adresse https: // stackoverflow .com / a / 48435532/895245 , mettons à jour cette information à la prise en charge des remplacements.

Les restrictions relatives aux POD sont de plus en plus assouplies au fur et à mesure de l'évolution de la norme, mon objectif est de couvrir toutes les relaxations dans l'exemple via ifdefs.

libstdc ++ a fait quelques essais à: https://github.com/gcc-mirror/gcc/blob/gcc-8_2_0-release/libstdc%2B%2B-v3/testsuite/20_util/is_pod/ value.cc mais trop peu. Mainteneurs: veuillez fusionner ceci si vous lisez ce post. Je suis paresseux pour consulter tous les projets de la suite de tests C ++ mentionnés sur: https://softwareengineering.stackexchange.com/questions/199708/is-there-a-compliance-test-for-c-compilers

#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
        // https://stackoverflow.com/questions/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.
        // https://stackoverflow.com/questions/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:
            // https://stackoverflow.com/questions/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:
    // 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<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
        // https://stackoverflow.com/questions/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
}

  

Pourquoi devons-nous différencier les POD des non-POD?

C ++ a commencé sa vie comme une extension de C. Alors que le C ++ moderne n’est plus un sur-ensemble strict de C, les utilisateurs s’attendent toujours à un haut niveau de compatibilité entre les deux.

Grosso modo, un type de POD est un type compatible avec C et peut-être tout aussi important avec certaines optimisations ABI.

Pour être compatible avec C, nous devons satisfaire deux contraintes.

  1. La mise en page doit être identique au type C correspondant.
  2. Le type doit être passé et renvoyé des fonctions de la même manière que le type C. correspondant.

Certaines fonctionnalités C ++ sont incompatibles avec cela.

Les méthodes virtuelles nécessitent que le compilateur insère un ou plusieurs pointeurs dans les tables de méthodes virtuelles, ce qui n’existe pas en C.

Les constructeurs de copie définis par l'utilisateur, les constructeurs de déplacement, les assignations de copie et les destructeurs ont des implications pour le passage et le retour de paramètres. De nombreuses ABI C passent et renvoient de petits paramètres dans des registres, mais les références transmises au constructeur / assigment / destructor défini par l'utilisateur ne peuvent fonctionner qu'avec des emplacements de mémoire.

Il est donc nécessaire de définir quels types peuvent être considérés comme "compatibles avec C". et quels types ne peuvent pas. C ++ 03 était un peu trop strict à cet égard. C ++ 11 a ouvert un peu les choses.

Avec C ++, Plain Old Data ne signifie pas seulement que des éléments tels que int, char, etc. sont les seuls types utilisés. Plain Old Data signifie en pratique que vous pouvez prendre une structure en la mémorisant d’un endroit à l’autre et les choses fonctionneront exactement comme vous le souhaiteriez (c’est-à-dire ne pas exploser). Cela se brise si votre classe, ou toute classe que contient votre classe, a pour membre un pointeur, une référence ou une classe ayant une fonction virtuelle. Essentiellement, si des pointeurs doivent être impliqués quelque part, ce n'est pas de simples données anciennes.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top