Что такое типы POD в С++?

Я встречал этот термин POD-type несколько раз. Что это значит?

Ответ 1

POD означает Plain Old Data, то есть класс (независимо от того, задано ли оно с ключевым словом struct или ключевым словом class) без конструкторов, деструкторов и функций виртуальных членов. Статья в Википедии о POD немного подробнее и определяет ее как:

Обычная старая структура данных в С++ представляет собой совокупный класс, который содержит только PODS в качестве членов, не имеет определяемого пользователем деструктора, не определяемого пользователем оператора назначения копирования и нестационарных членов типа указатель-член.

Более подробную информацию можно найти в этом ответе для С++ 98/03. С++ 11 изменил правила, связанные с POD, значительно расслабив их, таким образом потребовав последующий ответ здесь.

Ответ 2

Очень неформально

POD - это тип (включая классы), в котором компилятор C++ гарантирует, что в структуре не будет никакого "волшебства": например, скрытые указатели на vtables, смещения, которые применяются к адресу, когда он приводится к другому. типы (по крайней мере, если целевой POD тоже), конструкторы или деструкторы. Грубо говоря, тип - это POD, когда в нем есть только встроенные типы и их комбинации. Результатом является то, что "действует как" тип Си.

Менее неформально:

  • int, char, wchar_t, bool, float, double - это POD, а также их long/short и signed/unsigned версии.
  • указатели (включая указатель на функцию и указатель на член) являются POD,
  • enums являются PODами
  • const или volatile POD является POD.
  • class, struct или union POD - это 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-структура - это агрегатный класс, который не имеет нестатических членов-данных типа non-POD-struct, non-POD-union (или массива таких типов) или ссылки, и не имеет пользовательских определить оператор копирования и не определяемый пользователем деструктор. Аналогично POD-объединение - это совокупное объединение, которое не имеет нестатических членов-данных типа non-POD-struct, non-POD-union (или массива таких типов) или ссылки, и не имеет пользовательского оператора копирования и пользовательского деструктора.

8.5.1 (1): "Агрегат - это массив или класс (раздел 9) без объявленных пользователем конструкторов (12.1), без закрытых или защищенных нестатических элементов данных (раздел 11), без базовых классов (раздел 10) и никаких виртуальных функций (10.3). "

Ответ 3

Обычные старые данные

Вкратце, это все встроенные типы данных (например, int, char, float, long, unsigned char, double и т.д.) И все агрегации данных POD. Да, это рекурсивное определение. ;)

Чтобы быть более понятным, POD - это то, что мы называем "структурой": блок или группа блоков, которые просто хранят данные.

Ответ 4

Как я понимаю, 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)


Справка:

Ответ 5

Объект POD (простые старые данные) имеет один из этих типов данных - фундаментальный тип, указатель, объединение, структура, массив или класс - без конструктора. И наоборот, объект не-POD - это объект, для которого существует конструктор. Объект POD начинает свою жизнь, когда он получает хранилище с соответствующим размером для своего типа, и его срок службы заканчивается, когда хранилище для объекта повторно используется или освобождается.

Типы PlainOldData также не должны иметь:

  • Виртуальные функции (их собственные или унаследованные)
  • Виртуальные базовые классы (прямые или косвенные).

Более слабое определение PlainOldData включает объекты с конструкторами; но исключает тех, у кого есть виртуальное. Важная проблема с типами PlainOldData заключается в том, что они не являются полиморфными. Наследование может выполняться с помощью типов POD, однако это должно быть сделано только для реализацииInheritance (повторное использование кода), а не для полиморфизма/подтипирования.

Общее (хотя и не строго правильное) определение состоит в том, что тип PlainOldData - это то, что не имеет VeeTable.

Ответ 6

Примеры всех случаев не POD с static_assert от C++ 11 до C++ 17 и эффектами POD

std::is_pod был добавлен в C++ 11, поэтому давайте рассмотрим этот стандарт и далее.

std::is_pod будет удален из C++ 20, как упомянуто в fooobar.com/questions/535/..., давайте обновлять его по мере поступления поддержки для замен.

Ограничения POD становились все более и более смягченными по мере развития стандарта, я стремлюсь охватить все варианты расслабления в примере с помощью ifdefs.

libstdc++ немного протестировал: https://github.com/gcc-mirror/gcc/blob/gcc-8_2_0-release/libstdc%2B%2B-v3/testsuite/20_util/is_pod/value.cc, но слишком мало. Сопровождающие: пожалуйста, объедините это, если вы читаете этот пост. Мне лень проверять все проекты C++ testsuite, упомянутые на: 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 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 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.

Протестировано с:

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

  Почему мы должны различать POD и не POD вообще?

C++ начал свою жизнь как расширение C. Хотя современный C++ больше не является строгим надмножеством C, люди все еще ожидают высокого уровня совместимости между ними.

Грубо говоря, POD-тип - это тип, который совместим с C и, что не менее важно, совместим с некоторыми оптимизациями ABI.

Чтобы быть совместимым с C, нам нужно выполнить два ограничения.

  1. Макет должен быть таким же, как и соответствующий тип C.
  2. Тип должен передаваться и возвращаться из функций так же, как и соответствующий тип C.

Некоторые функции C++ несовместимы с этим.

Виртуальные методы требуют, чтобы компилятор вставлял один или несколько указателей в таблицы виртуальных методов, чего нет в C.

Определяемые пользователем конструкторы копирования, конструкторы перемещения, назначения копирования и деструкторы имеют значение для передачи и возврата параметров. Многие C ABI передают и возвращают небольшие параметры в регистрах, но ссылки, передаваемые пользовательскому конструктору/ассигменту/деструктору, могут работать только с ячейками памяти.

Поэтому необходимо определить, какие типы могут быть "совместимыми с C", а какие нет. C++ 03 был несколько чрезмерно строгим в этом отношении, любой определяемый пользователем конструктор отключал бы встроенные конструкторы, и любая попытка добавить их обратно приводила бы к тому, что они определялись пользователем и, следовательно, тип не являлся pod. C++ 11 довольно многое открыл, позволив пользователю заново представить встроенные конструкторы.

Ответ 8

Концепция POD и черты типа std::is_pod будут устаревать в С++ 20. См. этот вопрос для получения дополнительной информации.

Ответ 9

С С++ обычные обычные данные не просто означают, что такие вещи, как int, char и т.д., являются единственными используемыми типами. Обычные старые данные на самом деле означают на практике, что вы можете взять структуру memcpy из одного места в памяти в другое, и все будет работать точно так, как вы ожидали бы (т.е. Не взорвать). Это прерывается, если ваш класс или любой класс, который содержит ваш класс, имеет член, который является указателем или ссылкой или классом, который имеет виртуальную функцию. По существу, если указатели должны быть задействованы где-то, это не обычные старые данные.