Тривиальные типы, типы стандартной структуры, POD и типы литераловTrivial, standard-layout, POD, and literal types

Термин структура относится к организации членов объекта класса, структуры или типа объединения в памяти.The term layout refers to how the members of an object of class, struct or union type are arranged in memory. В некоторых случаях структура четко определена спецификациями языка.In some cases, the layout is well-defined by the language specification. Однако если класс или структура содержит определенные возможности языка C++, такие как виртуальные базовые классы, виртуальные функции, члены с разным уровнем управления доступом, компилятор может выбрать структуру самостоятельно.But when a class or struct contains certain C++ language features such as virtual base classes, virtual functions, members with different access control, then the compiler is free to choose a layout. Эта структура может сильно отличаться в зависимости от того, какие оптимизации выполняются, и во многих случаях объект может даже не занимать непрерывную область памяти.That layout may vary depending on what optimizations are being performed and in many cases the object might not even occupy a contiguous area of memory. Например, если класс имеет виртуальные функции, все экземпляры этого класса могут иметь одну общую таблицу виртуальных функций.For example, if a class has virtual functions, all the instances of that class might share a single virtual function table. Такие типы очень удобны, однако им присущи определенные ограничения.Such types are very useful, but they also have limitations. Поскольку структура не определена, их нельзя передавать программам, написанным на других языках, таких как C, а из-за того что они могут быть ненепрерывными, для них не поддерживается надежное копирование с помощью быстрых низкоуровневых функций, таких как memcopy, или сериализация по сети.Because the layout is undefined they cannot be passed to programs written in other languages, such as C, and because they might be non-contiguous they cannot be reliably copied with fast low-level functions such as memcopy, or serialized over a network.

Чтобы дать возможность компиляторам, а также программам и метапрограммам C++ определять пригодность того или иного типа для операций, зависящих от конкретной структуры памяти, в C++14 представлены три категории простых классов и структур: тривиальные, стандартной структуры и POD (простые старые данные).To enable compilers as well as C++ programs and metaprograms to reason about the suitability of any given type for operations that depend on a particular memory layout, C++14 introduced three categories of simple classes and structs: trivial, standard-layout, and POD or Plain Old Data. Стандартная библиотека содержит шаблоны функций is_trivial<T>, is_standard_layout<T> и is_pod<T>, которые определяют, принадлежит ли данный тип данной категории.The Standard Library has the function templates is_trivial<T>, is_standard_layout<T> and is_pod<T> that determine whether a given type belongs to a given category.

Тривиальные типыTrivial types

Если класс или структура в C++ включает предоставляемые компилятором или явно задаваемые по умолчанию специальные функции-члены — это тривиальный тип.When a class or struct in C++ has compiler-provided or explicitly defaulted special member functions, then it is a trivial type. Он занимает непрерывную область памяти.It occupies a contiguous memory area. Он может иметь члены с разными спецификаторами доступа.It can have members with different access specifiers. В C++ компилятор может самостоятельно выбирать способ упорядочивания членов в этой ситуации.In C++, the compiler is free to choose how to order members in this situation. Таким образом вы можете копировать такие объекты с помощью memcopy, однако надежное использование их из программы на языке C невозможно.Therefore, you can memcopy such objects but you cannot reliably consume them from a C program. Тривиальный тип T можно скопировать в массив значений char или unsigned char и безопасно скопировать обратно в переменную T.A trivial type T can be copied into an array of char or unsigned char, and safely copied back into a T variable. Обратите внимание, что из-за требований к выравниванию, между членами типа могут существовать байты заполнения.Note that because of alignment requirements, there might be padding bytes between type members.

Тривиальные типы имеют тривиальный конструктор по умолчанию, тривиальный конструктор копирования, тривиальный оператор назначения копирования и тривиальный деструктор.Trivial types have a trivial default constructor, trivial copy constructor, trivial copy assignment operator and trivial destructor. В любом случае тривиальный означает, что конструктор, оператор или деструктор не предоставляется пользователем и принадлежит к классу, у которогоIn each case, trivial means the constructor/operator/destructor is not user-provided and belongs to a class that has

  • нет виртуальных функций или виртуальных базовых классов;no virtual functions or virtual base classes,

  • нет базовых классов с соответствующим нетривиальным конструктором, оператором или деструктором;no base classes with a corresponding non-trivial constructor/operator/destructor

  • нет членов данных типа класса с соответствующим нетривиальным конструктором, оператором или деструктором.no data members of class type with a corresponding non-trivial constructor/operator/destructor

Ниже приведены примеры тривиальных типов.The following examples show trivial types. В Trivial2 наличие конструктора Trivial2(int a, int b) требует указания конструктора по умолчанию.In Trivial2, the presence of the Trivial2(int a, int b) constructor requires that you provide a default constructor. Чтобы тип мог считаться тривиальным, необходимо явно задать конструктор по умолчанию.For the type to qualify as trivial, you must explicitly default that constructor.

struct Trivial
{
   int i;
private:
   int j;
};

struct Trivial2
{
   int i;
   Trivial2(int a, int b) : i(a), j(b) {}
   Trivial2() = default;
private:
   int j;   // Different access control
};

Типы стандартной структурыStandard layout types

Если класс или структура не содержит определенные возможности языка C++, такие как виртуальные функции, которых нет в языке C, и все элементы имеют один и тот же уровень управления доступом — это тип стандартной структуры.When a class or struct does not contain certain C++ language features such as virtual functions which are not found in the C language, and all members have the same access control, it is a standard-layout type. Его можно скопировать с помощью функции memcopy, а структура достаточно определена, чтобы его могли использовать программы на языке C.It is memcopy-able and the layout is sufficiently defined that it can be consumed by C programs. Типы стандартной структуры могут иметь определенные пользователем специальные функции-члены.Standard-layout types can have user-defined special member functions. Кроме того, типы стандартной структуры имеют следующие характеристики:In addition, standard layout types have these characteristics:

  • нет виртуальных функций или виртуальных базовых классов;no virtual functions or virtual base classes

  • все нестатические члены данных имеют один уровень управления доступом;all non-static data members have the same access control

  • все нестатические члены типа класса относятся к стандартному макету;all non-static members of class type are standard-layout

  • все базовые классы относятся к стандартной структуре;any base classes are standard-layout

  • нет базовых классов того же типа, что и первый нестатический член данных;has no base classes of the same type as the first non-static data member.

  • соответствуют одному из следующих условий:meets one of these conditions:

    • нет нестатических членов данных в наиболее производном классе и не более одного базового класса с нестатическими членами данных илиno non-static data member in the most-derived class and no more than one base class with non-static data members, or

    • нет базовых классов с нестатическими членами данных.has no base classes with non-static data members

Ниже показан пример кода типа стандартной структуры:The following code shows one example of a standard-layout type:

struct SL
{
   // All members have same access:
   int i;
   int j;
   SL(int a, int b) : i(a), j(b) {} // User-defined constructor OK
};

Последние два требования, возможно, проще проиллюстрировать на примере кода.The last two requirements can perhaps be better illustrated with code. В следующем примере, хотя Base относится к типу стандартной структуры, Derived не является стандартным макетом, так как он (наиболее производный класс) и Base имеют нестатические члены данных:In the next example, even though Base is standard-layout, Derived is not standard layout because both it (the most derived class) and Base have non-static data members:

struct Base
{
   int i;
   int j;
};

// std::is_standard_layout<<Derived> == false!
struct Derived : public Base
{
   int x;
   int y;
};

В этом примере Derived — тип стандартной структуры, поскольку у Base нет нестатических членов данных:In this example Derived is standard-layout because Base has no non-static data members:

struct Base
{
   void Foo() {}
};

// std::is_standard_layout<<Derived> == true
struct Derived : public Base
{
   int x;
   int y;
};

Производный класс также будет относиться к стандартной структуре, если у Base есть члены данных, а у Derived — только функции-члены.Derived would also be standard-layout if Base had the data members and Derived had only member functions.

Типы PODPOD types

Если класс или структура является тривиальным типом и типом стандартной структуры — это тип POD (обычные старые данные).When a class or struct is both trivial and standard-layout, it is a POD (Plain Old Data) type. Таким образом, распределение памяти для типов POD является непрерывным, и адрес каждого члена выше, чем адрес члена, объявленного до него, что дает возможность выполнять побайтовое копирование и двоичный ввод-вывод для этих типов.The memory layout of POD types is therefore contiguous and each member has a higher address than the member that was declared before it, so that byte for byte copies and binary I/O can be performed on these types. Скалярные типы, такие как int, также являются типами POD.Scalar types such as int are also POD types. Типы POD, которые являются классами, могут содержать только типы POD в качестве нестатических членов данных.POD types that are classes can have only POD types as non-static data members.

ПримерExample

В следующем примере показаны различия между тривиальными типами, типами стандартной структуры и POD:The following example shows the distinctions between trivial, standard-layout, and POD types:

#include <type_traits>
#include <iostream>

using namespace std;

struct B
{
protected:
   virtual void Foo() {}
};

// Neither trivial nor standard-layout
struct A : B
{
   int a;
   int b;
   void Foo() override {} // Virtual function
};

// Trivial but not standard-layout
struct C
{
   int a;
private:
   int b;   // Different access control
};

// Standard-layout but not trivial
struct D
{
   int a;
   int b;
   D() {} //User-defined constructor
};

struct POD
{
   int a;
   int b;
};

int main()
{
   cout << boolalpha;
   cout << "A is trivial is " << is_trivial<A>() << endl; // false
   cout << "A is standard-layout is " << is_standard_layout<A>() << endl;  // false

   cout << "C is trivial is " << is_trivial<C>() << endl; // true
   cout << "C is standard-layout is " << is_standard_layout<C>() << endl;  // false

   cout << "D is trivial is " << is_trivial<D>() << endl;  // false
   cout << "D is standard-layout is " << is_standard_layout<D>() << endl; // true

   cout << "POD is trivial is " << is_trivial<POD>() << endl; // true
   cout << "POD is standard-layout is " << is_standard_layout<POD>() << endl; // true

   return 0;
}

Типы литераловLiteral types

Тип литерала — это такой тип, макет которого может быть определен во время компиляции.A literal type is one whose layout can be determined at compile time. Ниже указаны типы литералов.The following are the literal types:

  • voidvoid
  • скалярные типыscalar types
  • Ссылкиreferences
  • Массивы void, скалярных типов или ссылокArrays of void, scalar types or references
  • Класс, имеющий тривиальный деструктор, а также один или несколько конструкторов constexpr, которые не являются конструкторами перемещений или копий.A class that has a trivial destructor, and one or more constexpr constructors that are not move or copy constructors. Кроме того, все его нестатические данные-члены и базовые классы должны быть типами литералов и не должны изменяться.Additionally, all its non-static data members and base classes must be literal types and not volatile.

См. такжеSee also

Основные концепцииBasic Concepts