guidelines - iso c++




Quali sono i tipi di POD in C++? (6)

Ho incontrato questo termine POD-type alcune volte. Cosa significa?


Molto informalmente:

Un POD è un tipo (incluse le classi) in cui il compilatore C ++ garantisce che non ci sarà "magia" nella struttura: ad esempio puntatori nascosti a vtables, offset che vengono applicati all'indirizzo quando viene lanciato su altri tipi ( almeno se il POD del target), costruttori o distruttori. In parole povere, un tipo è un POD quando le uniche cose in esso contenute sono tipi e combinazioni incorporati. Il risultato è qualcosa che "si comporta come" un tipo C.

Meno informalmente:

  • int , char , wchar_t , bool , float , double sono i POD, così come le versioni long/short e signed/unsigned .
  • i puntatori (inclusi pointer-to-function e pointer-to-member) sono POD,
  • enums sono i POD
  • un POD const o volatile è un POD.
  • una class , struct o union di POD è un POD a condizione che tutti i membri di dati non statici siano public e che non abbia classe di base e nessun costruttore, distruttore o metodo virtuale. I membri statici non smettono di essere un POD sotto questa regola. Questa regola è cambiata in C ++ 11 e alcuni membri privati ​​sono autorizzati: una classe con tutti i membri privati ​​può essere una classe POD?
  • Wikipedia ha torto nel dire che un POD non può avere membri di tipo pointer-to-member. O meglio, è corretto per la dicitura C ++ 98, ma TC1 ha reso esplicito che i puntatori a membro sono POD.

Formalmente (standard C ++ 03):

3.9 (10): "I tipi aritmetici (3.9.1), i tipi di enumerazione, i tipi di puntatore e il puntatore ai tipi di membro (3.9.2) e le versioni qualificate cv di questi tipi (3.9.3) sono tipi scalari del chiamante collettivamente. i tipi, i tipi POD-struct, i tipi POD-union (clausola 9), gli array di tali tipi e le versioni qualificate cv di questi tipi (3.9.3) sono collettivamente chiamati tipi POD "

9 (4): "Un POD-struct è una classe aggregata che non ha membri di dati non statici di tipo non POD-struct, non POD-union (o array di tali tipi) o riferimento, e non ha user- definire un operatore di copia e nessun distruttore definito dall'utente. Allo stesso modo un POD-union è un'unione aggregata che non ha membri di dati non statici di tipo non POD-struct, non POD-union (o array di tali tipi) o riferimento, e non ha un operatore di copia definito dall'utente né un distruttore definito dall'utente.

8.5.1 (1): "Un aggregato è un array o una classe (clausola 9) senza costruttori dichiarati dall'utente (12.1), nessun membro di dati non statici privato o protetto (clausola 11), nessuna classe di base (clausola 10) e nessuna funzione virtuale (10.3). "


Come ho capito POD (PlainOldData) è solo un dato grezzo - non ha bisogno di:

  • essere costruito,
  • essere distrutto,
  • avere operatori personalizzati.
  • Non deve avere funzioni virtuali,
  • e non deve ignorare gli operatori.

Come verificare se qualcosa è un POD? Bene, c'è una struttura per quello chiamato 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)>
  { };
}

(Dall'intestazione type_traits)


Riferimento:


Il concetto di POD e il tipo tratto std::is_pod saranno deprecati in C ++ 20. Vedi this domanda per ulteriori informazioni.


Un oggetto POD (plain old data) ha uno di questi tipi di dati - un tipo fondamentale, puntatore, unione, struct, array o classe - senza alcun costruttore. Viceversa, un oggetto non POD è uno per il quale esiste un costruttore. Un oggetto POD inizia il suo ciclo di vita quando ottiene lo spazio di archiviazione con le dimensioni appropriate per il suo tipo e il suo ciclo di vita termina quando lo spazio di archiviazione per l'oggetto viene riutilizzato o deallocato.

I tipi PlainOldData inoltre non devono avere nessuno dei:

  • Funzioni virtuali (proprie o ereditate)
  • Classi di base virtuali (dirette o indirette).

Una definizione più flessibile di PlainOldData include oggetti con costruttori; ma esclude quelli con qualcosa virtuale. Il problema importante con i tipi PlainOldData è che non sono polimorfici. L'ereditarietà può essere effettuata con i tipi POD, tuttavia dovrebbe essere eseguita solo per ImplementationInheritance (riutilizzo del codice) e non per polimorfismo / sottotipizzazione.

Una definizione comune (sebbene non strettamente corretta) è che un tipo PlainOldData è tutto ciò che non ha una VeeTable.


POD è l' acronimo di Plain Old Data , ovvero una classe (definita con la parola chiave struct o la parola chiave class ) senza funzioni di costruttori, distruttori e membri virtuali. L'articolo di Wikipedia su POD va un po 'più in dettaglio e lo definisce come:

Una semplice struttura dei dati obsoleti in C ++ è una classe aggregata che contiene solo PODS come membri, non ha un distruttore definito dall'utente, nessun operatore di assegnazione copia definito dall'utente e nessun membro non statico del tipo puntatore-membro.

Maggiori dettagli possono essere trovati in questa risposta per C ++ 98/03 . C ++ 11 ha cambiato le regole che circondano il POD, rilassandole notevolmente, richiedendo quindi una risposta di follow-up qui .


Esempi di tutti i possibili casi non POD con static_assert da C ++ 11 a C ++ 17

std::is_pod stato aggiunto in C ++ 11, quindi consideriamo lo standard in poi per ora.

std::is_pod sarà rimosso da C ++ 20 come menzionato su https://.com/a/48435532/895245 , aggiorniamolo come supporto per le sostituzioni.

Le restrizioni POD sono diventate sempre più rilassate con lo standard evoluto, mirando a coprire tutti i rilassamenti con l'esempio.

libstdc ++ ha un piccolo bit di testing su: https://github.com/gcc-mirror/gcc/blob/gcc-8_2_0-release/libstdc%2B%2B-v3/testsuite/20_util/is_pod/value.cc ma troppo poco Manutentori: si prega di unire questo se leggete questo post. Sono pigro per controllare tutti i progetti menzionati su: https://softwareengineering.stackexchange.com/questions/199708/is-there-a-compliance-test-for-c-compilers Se qualcuno ha realizzato un progetto del genere, lui o lei sarebbe diventata famosa.

Per favore aiutami a uccidere tutti i TODO mancanti con le tue modifiche, guru C ++.

#include <type_traits>
#include <vector>

int main() {
/* POD restrictions have become more and more relaxed as the standard evolved.
 *
 * std::is_pod was added in C++11, so let's consider that standard onwards for now.
 */
#if __cplusplus >= 201103L
    /* 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 i) {}
                    };
                    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& 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>());
            }

            /* 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 examples. Everything that does not fall in the non-POD examples. */
    {
        /* Can't get more POD than this. */
        {
            struct C {};
            static_assert(std::is_pod<C>());
        }

        /* Private member: became POD in C++11
         * https://.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
        }

        /* Standard library containers are not, for the most part (all?),
         * POD because they are not trivial, which can be seen directly from their
         * interface definition in the standard.
         * https://.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>>());
        }

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

GitHub a monte .

Testato con:

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

su Ubuntu 18.04.

Elenco di tutti gli effetti POD noti all'uomo

C'è già una lista su: https://.com/a/4178176/895245 ma voglio TUTTI con esempi o link ad esempi per lo meno, per favore modifica via:







c++-faq