Jakie są typy POD W C++?

Natknąłem się na ten termin POD-Typ kilka razy.
Co to znaczy?

Author: Arsen Khachaturyan, 2008-09-28

9 answers

POD oznacza zwykłe stare dane - to znaczy klasę (zdefiniowaną słowem kluczowym struct lub słowem kluczowym class) bez konstruktorów, destruktorów i funkcji wirtualnych członków. Artykuł Wikipedii NA POD jest nieco bardziej szczegółowy i definiuje go jako:

Zwykła stara Struktura danych w C++ jest klasą agregującą, która zawiera tylko pods jako członków, nie ma destruktora zdefiniowanego przez użytkownika, nie ma operatora przypisywania kopii zdefiniowanego przez użytkownika i nie ma elementów niestatycznych typu pointer-to-member.

Więcej szczegółów można znaleźć w tej odpowiedzi dla C++98/03. C++11 zmienił zasady otaczające POD, rozluźniając je znacznie, dlatego wymaga odpowiedzi następczej tutaj .

 744
Author: Greg Hewgill,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:21

Bardzo nieformalnie:

POD jest typem (w tym klasami), w którym kompilator C++ gwarantuje, że w strukturze nie będzie "magii": na przykład ukryte wskaźniki do vtables, offsety, które są stosowane do adresu, gdy jest on rzucany do innych typów (przynajmniej jeśli jest to POD celu), konstruktory lub destruktory. Z grubsza mówiąc, typ jest POD, gdy jedynymi rzeczami w nim są wbudowane typy i ich kombinacje. Rezultatem jest coś, co "działa jak" C Typ.

Mniej nieformalnie:

  • int, char, wchar_t, bool, float, double są to strąki, podobnie jak ich wersje long/short i signed/unsigned.
  • pointery (w tym pointer-to-function I pointer-to-member) to PODs,
  • enums są strąki
  • A const lub volatile POD to POD.
  • a class, struct lub union Pod jest POD pod warunkiem, że wszystkie niestatyczne elementy danych są public i nie ma klasy bazowej ani konstruktorów, destruktorów ani metod wirtualnych. Członkowie statyczni nie zatrzymują czegoś jako kapsuły zgodnie z tą zasadą. Ta zasada została zmieniona w C++11 i niektóre prywatne członkowie są dozwolone: czy klasa ze wszystkimi prywatnymi członkami może być klasą POD?
  • Wikipedia źle mówi, że POD nie może mieć członków typu pointer-to-member. A raczej, to jest poprawne dla C++98 sformułowanie, ale TC1 wyraźnie powiedział, że pointers-to-member są POD.

Formalnie (C++03 Standard):

3.9(10): "arytmetyka typy (3.9.1), typy wyliczeń, typy wskaźników i typy wskaźników do elementów (3.9.2) oraz wersje tych typów kwalifikowane przez cv (3.9.3) są zbiorczo typami skalarnymi wywołującymi. Typy skalarne, typy pod-struct, typy pod-union (klauzula 9), tablice takich typów i wersje tych typów kwalifikowane przez cv (3.9.3) są zbiorczo nazywane typami POD" {]}

9(4): "POD-struct jest klasą agregującą, która nie ma niestatycznych członków danych typu non-pod-struct, non-POD-union (lub tablicy takich types) lub reference i nie ma operatora kopiującego definiowanego przez użytkownika ani destruktora definiowanego przez użytkownika. Podobnie POD-union jest zbiorczą Unią, która nie ma niestatycznych elementów danych typu non-pod-struct, non-POD-union (lub tablicy takich typów) lub reference, i nie ma operatora kopiowania zdefiniowanego przez użytkownika ani destruktora zdefiniowanego przez użytkownika.

8.5.1(1): "Agregat jest tablicą lub klasą (klauzula 9) bez deklarowanych przez użytkownika konstruktorów( 12.1), bez prywatnych lub chronionych niestatycznych elementów danych (klauzula 11), brak klas bazowych (klauzula 10) i brak funkcji wirtualnych (10.3)."

 375
Author: Steve Jessop,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-20 09:12:55

Plain Old Data

W skrócie, są to wszystkie wbudowane typy danych (np. int, char, float, long, unsigned char, double, itd.) oraz wszystkie agregacje danych POD. Tak, to definicja rekurencyjna. ;)

Aby być bardziej zrozumiałym, POD jest czymś, co nazywamy "strukturą": jednostką lub grupą jednostek, które po prostu przechowują dane.

 25
Author: ugasoft,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-06 14:21:44

Dlaczego musimy w ogóle odróżniać kapsuły od kapsuły?

C++ rozpoczął swoje życie jako rozszerzenie C. Chociaż współczesny C++ nie jest już ścisłym supersetem C, ludzie nadal oczekują wysokiego poziomu kompatybilności między nimi. "C ABI" platformy często działa jako de facto standardowy Inter-language ABI dla innych języków na platformie.

Z grubsza mówiąc, Typ POD jest typem zgodnym z C i być może równie ważnym jest kompatybilny z niektórymi optymalizacjami ABI.

Aby być kompatybilnym z C, musimy spełnić dwa ograniczenia.

  1. układ musi być taki sam jak odpowiedni typ C.
  2. typ musi być przekazywany i zwracany z funkcji w taki sam sposób, jak odpowiedni typ C.

Niektóre funkcje C++ są z tym niezgodne.

Metody wirtualne wymagają od kompilatora Wstawienia jednego lub więcej wskaźników do tabel metod wirtualnych, co nie exist in C.

Definiowane przez użytkownika konstruktory kopiujące, konstruktory przenoszenia, przydziały kopiowania i destruktory mają wpływ na przekazywanie i zwracanie parametrów. Wiele C ABIs przekazuje i zwraca małe parametry w rejestrach, ale odniesienia przekazywane do zdefiniowanego przez użytkownika konstruktora / asystenta/destruktora mogą działać tylko z lokalizacjami pamięci.

Istnieje więc potrzeba zdefiniowania, jakich typów można oczekiwać jako "kompatybilnych z C", a jakich typów nie. C++03 był w tym względzie nieco zbyt surowy, każdy konstruktor zdefiniowany przez użytkownika wyłączyłby wbudowane konstruktory, a każda próba dodania ich z powrotem spowodowałaby, że zostaną zdefiniowane przez użytkownika, a zatem typ nie będzie pod. C++11 otworzył wiele rzeczy, pozwalając użytkownikowi na ponowne wprowadzenie wbudowanych konstruktorów.

 15
Author: plugwash,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-12-07 21:25:28

Jak rozumiem POD (PlainOldData) jest tylko surowymi danymi - nie potrzebuje:

  • do zbudowania,
  • do zniszczenia,
  • aby mieć operatorów niestandardowych.
  • nie może mieć funkcji wirtualnych,
  • i nie mogą nadpisywać operatorów.

Jak sprawdzić, czy coś jest POD? Cóż, istnieje struct dla tego o nazwie 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)>
  { };
}

(z nagłówka type_traits)


odniesienie:

 12
Author: набиячлэвэли,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-20 18:10:56

Obiekt POD (plain old data) posiada jeden z tych typów danych-Typ podstawowy, wskaźnik, union, struct, tablica lub klasa-bez konstruktora. Odwrotnie, obiekt nie-POD to obiekt, dla którego istnieje konstruktor. Obiekt POD rozpoczyna swój okres eksploatacji, gdy uzyska pamięć masową o rozmiarze odpowiednim dla jego typu, a jego okres eksploatacji kończy się, gdy pamięć masowa obiektu zostanie ponownie użyta lub usunięta.

Typy PlainOldData również nie mogą mieć żadnego z:

  • funkcje wirtualne (albo własne lub odziedziczone)
  • wirtualne klasy bazowe (bezpośrednie lub pośrednie).

Luźniejsza definicja PlainOldData obejmuje obiekty z konstruktorami; ale wyklucza obiekty z czymkolwiek wirtualnym. Ważną kwestią w przypadku typów PlainOldData jest to, że nie są one polimorficzne. Dziedziczenie może być wykonywane z typami POD, jednak powinno być wykonywane tylko dla implementacji (ponownego użycia kodu), a nie polimorfizmu/podtypowania.

Powszechną (choć nie do końca poprawną) definicją jest że typ PlainOldData to coś, co nie ma VeeTable.

 10
Author: amitabes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-16 11:56:51

Przykłady wszystkich przypadków nie-POD z static_assert od C++11 do C++17 i efektów POD

std::is_pod został dodany w C++11, więc rozważmy ten standard na razie.

std::is_pod zostanie usunięty z C++20 Jak wspomniano w https://stackoverflow.com/a/48435532/895245 , zaktualizujmy to, gdy pojawi się wsparcie dla zamienników.

Ograniczenia POD stają się coraz bardziej zrelaksowane w miarę rozwoju standardu, staram się objąć wszystkie relaksacje w przykładzie poprzez ifdefs.

Libstdc++ ma at tiny bit of testing at: https://github.com/gcc-mirror/gcc/blob/gcc-8_2_0-release/libstdc%2B%2B-v3/testsuite/20_util/is_pod/value.cc{[13] ale to za mało. Opiekunowie: proszę połączyć to, jeśli czytasz ten post. Jestem leniwy, aby sprawdzić wszystkie projekty testsuite C++ Wymienione na: 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
}

GitHub upstream .

Sprawdzone przez:

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

Na Ubuntu 18.04, GCC 8.2.0.

 10
Author: Ciro Santilli TRUMP BAN IS BAD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-11-16 06:57:24

Pojęcie POD i cecha typu std::is_pod będą przestarzałe w C++20. Zobacz to pytanie , aby uzyskać więcej informacji.

 5
Author: ThomasMcLeod,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-25 04:09:04

W C++ zwykłe stare dane nie oznaczają tylko, że rzeczy takie jak int, char itp.są jedynymi używanymi typami. Zwykłe stare dane naprawdę oznaczają w praktyce, że możesz przenieść STRUCT memcpy z jednego miejsca w pamięci do drugiego i wszystko będzie działać dokładnie tak ,jak byś się spodziewał(tzn. nie wysadzać). Jest to złamane, jeśli twoja klasa lub jakakolwiek klasa zawiera klasę, która jest wskaźnikiem, referencją lub klasą, która ma funkcję wirtualną. Zasadniczo, jeśli trzeba zaangażować gdzieś, to nie są zwykłe stare dane.

 -7
Author: Mark Kegel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-28 20:14:11