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

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

Также см. http://stackoverflow.com/questions/2293796

Lazer 13.06.2010 11:16

см. chat.stackoverflow.com/transcript/message/213026#213026 и сообщения следующего дня для обсуждения принятого ответа

Johannes Schaub - litb 22.12.2010 13:51

Также stackoverflow.com/questions/4178175/…

Mihran Hovsepyan 23.06.2011 12:45

@ paxos1977: Измените свой выбор «решения» (в настоящее время ответ Хьюгилла), чтобы принципиально неправильный ответ не вводил в заблуждение гуглеров, оказавшихся здесь.

Cheers and hth. - Alf 16.08.2016 03:15

Мы пришли к выводу, что строка в стиле c НЕ является типом POD, потому что 1.) указатель не является смежным со строковыми данными и 2.) чтобы сделать строку типом POD, вам необходимо убедиться, что тип имел в нем нулевой символ в пределах предопределенного размера типа POD, что приводило к неопределенному поведению.

user2356685 25.05.2018 06:53

@ user2356685 что ты имеешь в виду и кто мы? Есть указатель на строку и хранилище, в котором расположен массив символов, оба обрабатываются как тривиальные данные. Структура, которая содержит указатель на char, по-прежнему является POD, тот факт, что она не владеет хранилищем строк, является другим, не связанным с этим фактом.

Swift - Friday Pie 25.04.2019 20:22
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1 057
6
340 256
9
Перейти к ответу Данный вопрос помечен как решенный

Ответы 9

Ответ принят как подходящий

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

A Plain Old Data Structure in C++ is an aggregate class that contains only PODS as members, has no user-defined destructor, no user-defined copy assignment operator, and no nonstatic members of pointer-to-member type.

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

Хммм ... Думаю, я предпочитаю более правильный технический термин "внутренний тип" подобному сленгу. ;)

paxos1977 28.09.2008 22:41

Есть разница. Внутренние типы - это «встроенные» языковые примитивы. Это типы POD, а также их агрегаты (и другие POD).

Adam Wright 28.09.2008 22:44

POD: int, char, float и т. д. Встроенные типы.

Martin York 28.09.2008 23:52

@Greg Hewgill: Почему нам вообще нужно различать POD и не POD?

Lazer 13.06.2010 11:53

Типы POD имеют характеристики, которых нет у типов, отличных от POD. Например, если у вас есть глобальная, константная структура типа POD, вы можете инициализировать ее содержимое с помощью фигурных скобок, она помещается в память только для чтения, и не нужно создавать код для ее инициализации (конструктор или иначе), потому что это часть образа программы. Это важно для разработчиков встраиваемых систем, которые часто имеют жесткие ограничения на RAM, ROM или Flash.

Mike DeSimone 14.11.2010 21:11

В C++ 11 вы можете выполнить std :: is_pod <MyType> (), чтобы определить, является ли MyType POD.

allyourcode 01.04.2014 01:24

В Технический отчет о производительности C++ Бьярна Страуструпа говорится, что стандарт C++ описывает POD как «тип данных, который совместим с эквивалентным типом данных в C в макете, инициализации и его способность копироваться с помощью memcpy». Возможно, следует проводить различие между типом POD и структурой POD.

user34660 13.01.2015 22:59
−1 This answer is still fundamentally wrong & misleading as of 16th Aug 2016: POD types are not restricted to be class types.
Cheers and hth. - Alf 16.08.2016 03:13

А что насчет струны? Строки находятся на C, но вы не можете просто скопировать их с помощью memcpy.

user2356685 16.05.2018 04:50

Строка по умолчанию является строкой ASCII, а UTF-8 не является встроенной. Строка может использовать базовый класс UTF-8 с подклассом UTF-16 и UTF-32. Согласно этому определению не все строки являются типами POD. Если не все строки являются типами POD, тогда строки по определению не будут типами POD. Никто не упоминает строки в аргументе POD, вероятно, именно по этой причине. Где врачи?

user2356685 16.05.2018 05:18

Итак, по этому определению String не является POD, потому что вы не можете скопировать его напрямую с помощью memcpy.

user2356685 25.05.2018 06:50

@Cale В C. нет такой вещи, как "строковый" тип. Есть char *, но существенное различие между ними состоит в том, что хотя сам тип на самом деле является типом POD, его концептуальная ценность - то есть то, что вы думаете о нем, представляет этот массив персонажи - не POD по указанным вами причинам. Фактический указатель, char *, который вы передаете, в основном представляет собой целое число в маскарадном костюме и работает так же, как и int, для определения того, является ли что-то типом POD. Однако, чтобы скопировать концептуальная строка, который он представляет, да, вам нужно сделать больше.

Fund Monica's Lawsuit 26.06.2018 23:54

@NicHartley: Это критический момент. Массив символов - это POD, а в C это все, что у вас есть. Концепция «строки» - это артефакт библиотеки функций, обрабатывающих массивы символов с нулевым символом в конце.

David C. 27.02.2019 21:59

POD звучит очень похоже на непреобразуемые типы C#

zwcloud 13.04.2020 12:40

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

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

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

Это правда, что мы иногда называем их «структурой». Однако мы всегда ошибаемся, поскольку структура не обязательно является POD-типом.

Steve Jessop 28.09.2008 23:21

очевидно ... структура и класс почти эквивалентны, но в «бизнесе» мы называем «структурой» простой сборщик данных, обычно без ctors и dtor, обычно с семантикой значений ...

ugasoft 29.09.2008 01:52

Для меня было неправильным C++ делать структуру идентичной ключевому слову class или близкой к: struct только добавляет публичный доступ по умолчанию к классу. Мне было проще создавать C-подобные структуры, и у нас были бы POD в нулевой день C++.

user1708042 16.09.2015 15:14

ugasoft: ваш ответ может вводить в заблуждение - в вашем комментарии поясняется недостающая деталь, которая так используется на практике, а не стандартно. Эй, 8 лет, ты вообще здесь? ;-)

hauron 10.03.2016 11:14

За исключением строки, потому что вы не можете скопировать ее с помощью memcpy без предварительного определения длины строки.

user2356685 25.05.2018 06:51

@ugasoft на самом деле структура и класс не эквивалентны, потому что все переменные, объявленные в структуре, являются общедоступными, тогда как в классе вы также можете иметь частные переменные, поэтому использование структуры может привести к проблемам безопасности в долгосрочной перспективе, поэтому они не очень часто используется в ООП.

Yunfei Chen 02.07.2020 00:05

Может ли кто-нибудь прояснить мне, что такое ctors и dtor, потому что я никогда не видел их в структурах или видел структуру, называемую простым сборщиком данных ???

Yunfei Chen 02.07.2020 00:06

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

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

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

  • 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): "Arithmetic types (3.9.1), enumeration types, pointer types, and pointer to member types (3.9.2) and cv-qualified versions of these types (3.9.3) are collectively caller scalar types. Scalar types, POD-struct types, POD-union types (clause 9), arrays of such types and cv-qualified versions of these types (3.9.3) are collectively called POD types"

9(4): "A POD-struct is an aggregate class that has no non-static data members of type non-POD-struct, non-POD-union (or array of such types) or reference, and has no user-define copy operator and no user-defined destructor. Similarly a POD-union is an aggregate union that has no non-static data members of type non-POD-struct, non-POD-union (or array of such types) or reference, and has no user-define copy operator and no user-defined destructor.

8.5.1(1): "An aggregate is an array or class (clause 9) with no user-declared constructors (12.1), no private or protected non-static data members (clause 11), no base classes (clause 10) and no virtual functions (10.3)."

У вас формальный / менее формальный. Вы можете добавить практическое правило. Встроенные типы и агрегаты встроенных типов (или что-то в этом роде). В дополнение к точному определению нам необходимо упростить использование знаний.

Martin York 28.09.2008 23:58

Я добавил пункт «грубо говоря». Я не хочу говорить «совокупность», потому что это жаргонный термин, и случайный читатель не узнает, что это означает отсутствие виртуальных функций, закрытых членов и т. д.

Steve Jessop 29.09.2008 00:08

Вы немного ошиблись с битом "смещения, когда cast_to другого типа". Эти смещения применяются при приведении к базовому или производному классу. Таким образом, если вы приведете указатель базового класса POD к классу, не являющемуся производным от POD, вы все равно можете столкнуться с корректировкой.

MSalters 29.09.2008 16:05

@ Стив Джессоп: Почему нам вообще нужно различать POD и не POD?

Lazer 13.06.2010 12:03

@Lazer: это совсем другой вопрос: «как ведут себя POD?» в отличие от «что означает POD?». Таким образом, разница связана с инициализацией (следовательно, также с использованием memcpy для дублирования объектов), совместимостью с макетом структуры C для этого компилятора и приведением указателя вверх и вниз. POD «действуют как типы C», а не-POD это не гарантируется. Поэтому, если вы хотите, чтобы ваш тип переносимо действовал как структура C, вы должны убедиться, что это POD, поэтому вам нужно знать разницу.

Steve Jessop 13.06.2010 22:13

@Lazer: (запоздалый, но) исчерпывающий ответ можно найти здесь: stackoverflow.com/questions/4178175/…

sbi 14.11.2010 21:46

Мне нравится этот. Я бы хотел, чтобы это было принято. Очень хорошо! Мне нравится, как первый абзац соответствует описанию «POF» («старая добрая функция», термин, также определенный в Стандарте).

Johannes Schaub - litb 22.12.2010 13:22

@muntoo: это было, правда, я комментировал ответ, в котором цитируется устаревшая информация из Википедии. Полагаю, я мог бы отредактировать этот ответ, но я чувствую неприятность, если буду редактировать ответ других людей, чтобы согласиться с моим, независимо от того, насколько я прав.

Steve Jessop 17.06.2012 05:45

Так является ли строка типом POD или как? Все столбы не касаются предметов 10-футовой шестой. Это вопрос, который ВСЕ хотят знать ... Да, строка ASCII ЯВЛЯЕТСЯ встроенным типом, но как насчет строки UTF-16 или UTF-32? Они не встроены, но по-прежнему являются строками, и МОЖЕТ быть волшебство, происходящее за кулисами с методами объектно-ориентированного программирования (т. Е. Абстрактная строка, хранящаяся как UTF-8, а затем подкласса UTF-16 или UTF-32). Если один тип строки не является типом POD, то все они не являются типами POD по индукции.

user2356685 16.05.2018 05:08

@Cale: все строковые типы C++ имеют конструкторы, поэтому в определении C++ 03 они не являются агрегатами и, следовательно, не POD. Точно так же в моих определениях «очень неформально» и «менее неформально» говорится, что классы не могут быть POD, если у них есть конструктор. Для данного стандартного класса вы можете проверить, есть ли у него конструкторы, деструкторы, виртуальные функции-члены, базовые классы или операторы копирования, прочитав спецификацию для этого класса (или шаблона класса).

Steve Jessop 22.05.2018 16:31

Я и доктор моего друга из CS пришли к выводу, что вы можете «притвориться», что строка является типом POD, но для того, чтобы гарантировать наличие нулевого символа char, потребуется конструктор. Вы просто получите неопределенное поведение.

user2356685 25.05.2018 06:49

@Cale: представьте, что вам нравится :-) Есть несколько вещей, которые вам разрешено делать с POD, которые не будут работать со строками. Использование их без построения - это одно, но освобождение памяти без предварительного разрушения объекта - другое, а копирование объекта в новое место и его использование - третье.

Steve Jessop 26.05.2018 14:21

Вы упоминаете vtables, но не объясняете их. Вот отличная информация. на vptrs и vtbls: drdobbs.com/cpp/storage-layout-of-polymorphic-objects/240012‌ 098.

Gabriel Staples 29.08.2020 06:00

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

Указатели разрешены в структурах POD. Ссылки нет.

j_random_hacker 12.02.2009 09:37

Passant здесь отсутствует.

icbytes 17.09.2014 00:55

Насколько я понимаю, 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)

Ссылка:

Неправильно, тип POD может иметь функции-члены или перегруженные операторы. (Но он может не иметь виртуальных функций-членов.)

Colin D Bennett 20.05.2015 20:54

@ColinDBennett Да, это правда. Извините за путаницу. Отредактировано в / вне ответа.

набиячлэвэли 20.05.2015 21:08

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

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

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

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

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

Ваш ответ очень хороший, но на этот вопрос был принят ответ 8 лет назад, плюс еще несколько хороших ответов. Вы можете внести больший вклад в SO, если воспользуетесь своими знаниями, чтобы ответить на вопросы, на которые еще нет ответа)))

mvidelgauz 16.08.2016 15:03

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

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

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

std::is_pod будет удален из C++ 20, как упоминалось в https://stackoverflow.com/a/48435532/895245, давайте обновим это по мере поступления поддержки для замены.

По мере развития стандарта ограничения 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, но этого слишком мало. Сопровождающие: пожалуйста, объедините это, если вы читаете этот пост. Мне лень проверять все проекты 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'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 вверх по течению.

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

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.

Why do we need to differentiate between POD's and non-POD's at all?

C++ начал свою жизнь как расширение C. Хотя современный C++ больше не является строгим надмножеством C, люди по-прежнему ожидают высокого уровня совместимости между ними. «C ABI» платформы также часто действует как фактический стандартный межъязыковой ABI для других языков на платформе.

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

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

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

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

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

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

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

Другие вопросы по теме