Я встречал этот термин POD-тип несколько раз. Что это означает?
см. chat.stackoverflow.com/transcript/message/213026#213026 и сообщения следующего дня для обсуждения принятого ответа
Также stackoverflow.com/questions/4178175/…
@ paxos1977: Измените свой выбор «решения» (в настоящее время ответ Хьюгилла), чтобы принципиально неправильный ответ не вводил в заблуждение гуглеров, оказавшихся здесь.
Мы пришли к выводу, что строка в стиле c НЕ является типом POD, потому что 1.) указатель не является смежным со строковыми данными и 2.) чтобы сделать строку типом POD, вам необходимо убедиться, что тип имел в нем нулевой символ в пределах предопределенного размера типа POD, что приводило к неопределенному поведению.
@ user2356685 что ты имеешь в виду и кто мы? Есть указатель на строку и хранилище, в котором расположен массив символов, оба обрабатываются как тривиальные данные. Структура, которая содержит указатель на char, по-прежнему является POD, тот факт, что она не владеет хранилищем строк, является другим, не связанным с этим фактом.





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, значительно ослабив их, таким образом, требуя дополнительного ответа здесь.
Хммм ... Думаю, я предпочитаю более правильный технический термин "внутренний тип" подобному сленгу. ;)
Есть разница. Внутренние типы - это «встроенные» языковые примитивы. Это типы POD, а также их агрегаты (и другие POD).
POD: int, char, float и т. д. Встроенные типы.
@Greg Hewgill: Почему нам вообще нужно различать POD и не POD?
Типы POD имеют характеристики, которых нет у типов, отличных от POD. Например, если у вас есть глобальная, константная структура типа POD, вы можете инициализировать ее содержимое с помощью фигурных скобок, она помещается в память только для чтения, и не нужно создавать код для ее инициализации (конструктор или иначе), потому что это часть образа программы. Это важно для разработчиков встраиваемых систем, которые часто имеют жесткие ограничения на RAM, ROM или Flash.
В C++ 11 вы можете выполнить std :: is_pod <MyType> (), чтобы определить, является ли MyType POD.
В Технический отчет о производительности C++ Бьярна Страуструпа говорится, что стандарт C++ описывает POD как «тип данных, который совместим с эквивалентным типом данных в C в макете, инициализации и его способность копироваться с помощью memcpy». Возможно, следует проводить различие между типом POD и структурой POD.
А что насчет струны? Строки находятся на C, но вы не можете просто скопировать их с помощью memcpy.
Строка по умолчанию является строкой ASCII, а UTF-8 не является встроенной. Строка может использовать базовый класс UTF-8 с подклассом UTF-16 и UTF-32. Согласно этому определению не все строки являются типами POD. Если не все строки являются типами POD, тогда строки по определению не будут типами POD. Никто не упоминает строки в аргументе POD, вероятно, именно по этой причине. Где врачи?
Итак, по этому определению String не является POD, потому что вы не можете скопировать его напрямую с помощью memcpy.
@Cale В C. нет такой вещи, как "строковый" тип. Есть char *, но существенное различие между ними состоит в том, что хотя сам тип на самом деле является типом POD, его концептуальная ценность - то есть то, что вы думаете о нем, представляет этот массив персонажи - не POD по указанным вами причинам. Фактический указатель, char *, который вы передаете, в основном представляет собой целое число в маскарадном костюме и работает так же, как и int, для определения того, является ли что-то типом POD. Однако, чтобы скопировать концептуальная строка, который он представляет, да, вам нужно сделать больше.
@NicHartley: Это критический момент. Массив символов - это POD, а в C это все, что у вас есть. Концепция «строки» - это артефакт библиотеки функций, обрабатывающих массивы символов с нулевым символом в конце.
POD звучит очень похоже на непреобразуемые типы C#
Короче говоря, это все встроенные типы данных (например, int, char, float, long, unsigned char, double и т. д.) И все агрегации данных POD. Да, это рекурсивное определение. ;)
Чтобы быть более ясным, POD - это то, что мы называем «структурой»: единица или группа единиц, которые просто хранят данные.
Это правда, что мы иногда называем их «структурой». Однако мы всегда ошибаемся, поскольку структура не обязательно является POD-типом.
очевидно ... структура и класс почти эквивалентны, но в «бизнесе» мы называем «структурой» простой сборщик данных, обычно без ctors и dtor, обычно с семантикой значений ...
Для меня было неправильным C++ делать структуру идентичной ключевому слову class или близкой к: struct только добавляет публичный доступ по умолчанию к классу. Мне было проще создавать C-подобные структуры, и у нас были бы POD в нулевой день C++.
ugasoft: ваш ответ может вводить в заблуждение - в вашем комментарии поясняется недостающая деталь, которая так используется на практике, а не стандартно. Эй, 8 лет, ты вообще здесь? ;-)
За исключением строки, потому что вы не можете скопировать ее с помощью memcpy без предварительного определения длины строки.
@ugasoft на самом деле структура и класс не эквивалентны, потому что все переменные, объявленные в структуре, являются общедоступными, тогда как в классе вы также можете иметь частные переменные, поэтому использование структуры может привести к проблемам безопасности в долгосрочной перспективе, поэтому они не очень часто используется в ООП.
Может ли кто-нибудь прояснить мне, что такое ctors и dtor, потому что я никогда не видел их в структурах или видел структуру, называемую простым сборщиком данных ???
POD - это тип (включая классы), в котором компилятор C++ гарантирует, что в структуре не будет происходить «магия»: например, скрытые указатели на vtables, смещения, которые применяются к адресу, когда он приводится к другим типам ( по крайней мере, если целевой POD тоже), конструкторы или деструкторы. Грубо говоря, тип - это POD, когда в нем есть только встроенные типы и их комбинации. В результате получается что-то, что «действует как» тип C.
int, char, wchar_t, bool, float, double являются POD, а также их версии long/short и signed/unsigned.enums - это PODconst или volatile POD - это POD.class, struct или union POD является POD при условии, что все нестатические элементы данных являются public, и у него нет базового класса и конструкторов, деструкторов или виртуальных методов. Статические члены не мешают чему-то быть POD в соответствии с этим правилом. Это правило было изменено в C++ 11, и разрешены некоторые закрытые члены: Может ли класс со всеми закрытыми членами быть классом POD?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)."
У вас формальный / менее формальный. Вы можете добавить практическое правило. Встроенные типы и агрегаты встроенных типов (или что-то в этом роде). В дополнение к точному определению нам необходимо упростить использование знаний.
Я добавил пункт «грубо говоря». Я не хочу говорить «совокупность», потому что это жаргонный термин, и случайный читатель не узнает, что это означает отсутствие виртуальных функций, закрытых членов и т. д.
Вы немного ошиблись с битом "смещения, когда cast_to другого типа". Эти смещения применяются при приведении к базовому или производному классу. Таким образом, если вы приведете указатель базового класса POD к классу, не являющемуся производным от POD, вы все равно можете столкнуться с корректировкой.
@ Стив Джессоп: Почему нам вообще нужно различать POD и не POD?
@Lazer: это совсем другой вопрос: «как ведут себя POD?» в отличие от «что означает POD?». Таким образом, разница связана с инициализацией (следовательно, также с использованием memcpy для дублирования объектов), совместимостью с макетом структуры C для этого компилятора и приведением указателя вверх и вниз. POD «действуют как типы C», а не-POD это не гарантируется. Поэтому, если вы хотите, чтобы ваш тип переносимо действовал как структура C, вы должны убедиться, что это POD, поэтому вам нужно знать разницу.
@Lazer: (запоздалый, но) исчерпывающий ответ можно найти здесь: stackoverflow.com/questions/4178175/…
Мне нравится этот. Я бы хотел, чтобы это было принято. Очень хорошо! Мне нравится, как первый абзац соответствует описанию «POF» («старая добрая функция», термин, также определенный в Стандарте).
@muntoo: это было, правда, я комментировал ответ, в котором цитируется устаревшая информация из Википедии. Полагаю, я мог бы отредактировать этот ответ, но я чувствую неприятность, если буду редактировать ответ других людей, чтобы согласиться с моим, независимо от того, насколько я прав.
Так является ли строка типом POD или как? Все столбы не касаются предметов 10-футовой шестой. Это вопрос, который ВСЕ хотят знать ... Да, строка ASCII ЯВЛЯЕТСЯ встроенным типом, но как насчет строки UTF-16 или UTF-32? Они не встроены, но по-прежнему являются строками, и МОЖЕТ быть волшебство, происходящее за кулисами с методами объектно-ориентированного программирования (т. Е. Абстрактная строка, хранящаяся как UTF-8, а затем подкласса UTF-16 или UTF-32). Если один тип строки не является типом POD, то все они не являются типами POD по индукции.
@Cale: все строковые типы C++ имеют конструкторы, поэтому в определении C++ 03 они не являются агрегатами и, следовательно, не POD. Точно так же в моих определениях «очень неформально» и «менее неформально» говорится, что классы не могут быть POD, если у них есть конструктор. Для данного стандартного класса вы можете проверить, есть ли у него конструкторы, деструкторы, виртуальные функции-члены, базовые классы или операторы копирования, прочитав спецификацию для этого класса (или шаблона класса).
Я и доктор моего друга из CS пришли к выводу, что вы можете «притвориться», что строка является типом POD, но для того, чтобы гарантировать наличие нулевого символа char, потребуется конструктор. Вы просто получите неопределенное поведение.
@Cale: представьте, что вам нравится :-) Есть несколько вещей, которые вам разрешено делать с POD, которые не будут работать со строками. Использование их без построения - это одно, но освобождение памяти без предварительного разрушения объекта - другое, а копирование объекта в новое место и его использование - третье.
Вы упоминаете vtables, но не объясняете их. Вот отличная информация. на vptrs и vtbls: drdobbs.com/cpp/storage-layout-of-polymorphic-objects/240012 098.
В C++ Plain Old Data не просто означает, что используются только такие типы, как int, char и т. д. Простые старые данные на практике означают, что вы можете перенести структуру из одного места памяти в другое, и все будет работать точно так, как вы ожидаете (т.е.не взорваться). Это прерывается, если ваш класс или любой класс, содержащийся в вашем классе, имеет в качестве члена указатель, ссылку или класс, который имеет виртуальную функцию. По сути, если где-то должны быть задействованы указатели, это не обычные старые данные.
Указатели разрешены в структурах POD. Ссылки нет.
Passant здесь отсутствует.
Насколько я понимаю, 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 может иметь функции-члены или перегруженные операторы. (Но он может не иметь виртуальных функций-членов.)
@ColinDBennett Да, это правда. Извините за путаницу. Отредактировано в / вне ответа.
Объект POD (простые старые данные) имеет один из этих типов данных - основной тип, указатель, объединение, структура, массив или класс - без конструктора. И наоборот, объект, не относящийся к POD, - это объект, для которого существует конструктор. Объект POD начинает свое время жизни, когда он получает хранилище с надлежащим размером для своего типа, и его время жизни заканчивается, когда хранилище для объекта либо повторно используется, либо освобождается.
Типы PlainOldData также не должны иметь:
Более свободное определение PlainOldData включает объекты с конструкторами; но исключает тех, у кого есть виртуальное что-нибудь. Важная проблема с типами PlainOldData заключается в том, что они не полиморфны. Наследование может быть выполнено с типами POD, однако оно должно выполняться только для ImplementationInheritance (повторное использование кода), а не полиморфизма / подтипов.
Распространенное (хотя и не совсем правильное) определение состоит в том, что тип PlainOldData - это все, что не имеет VeeTable.
Ваш ответ очень хороший, но на этот вопрос был принят ответ 8 лет назад, плюс еще несколько хороших ответов. Вы можете внести больший вклад в SO, если воспользуетесь своими знаниями, чтобы ответить на вопросы, на которые еще нет ответа)))
Концепция 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
}
Протестировано с:
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, нам нужно удовлетворить два ограничения.
Некоторые функции C++ несовместимы с этим.
Виртуальные методы требуют, чтобы компилятор вставил один или несколько указателей в таблицы виртуальных методов, чего нет в C.
Определяемые пользователем конструкторы копирования, конструкторы перемещения, присваивания копий и деструкторы имеют значение для передачи и возврата параметров. Многие C ABI передают и возвращают небольшие параметры в регистрах, но ссылки, передаваемые в определяемый пользователем конструктор / присваивание / деструктор, могут работать только с ячейками памяти.
Таким образом, необходимо определить, какие типы могут считаться «C-совместимыми», а какие - нет. C++ 03 был несколько чрезмерно строгим в этом отношении: любой определяемый пользователем конструктор отключал бы встроенные конструкторы, и любая попытка добавить их обратно привела бы к тому, что они были бы определяемыми пользователем и, следовательно, типом, отличным от pod. C++ 11 несколько открыл новые возможности, позволив пользователю повторно ввести встроенные конструкторы.
Также см. http://stackoverflow.com/questions/2293796