тривіальний проти стандартного макета проти POD


77

Якщо говорити неспеціалістами, у чому різниця між тривіальними типами, типовими типами компонування та POD?

Зокрема, я хочу визначити, чи new Tвідрізняється він від new T()будь-якого параметра шаблону T. Який із типів рис is_trivial, is_standard_layoutі чи is_podварто обирати?

(Як побічне питання, чи можна будь-яку з цих властивостей типу реалізувати без магії компілятора?)


3
Я думаю, це трохи пізно згадувати про це. Але для людей, які шукають детально розроблену відповідь, ось посилання. Перевірте відповідь на R Martinho Fernandes stackoverflow.com/questions/4178175 / ...
jmishra

Відповіді:


67

Я не думаю, що це можна зробити по-справжньому неспеціалістично, принаймні без великої кількості додаткового пояснення. Одним з важливих моментів є статична та динамічна ініціалізація, але пояснити, що для неспеціаліста це буде кілька сторінок саме по собі ...

PODs (помилково) визначено в C ++ 98. Тут дійсно є два окремі наміри, які не виражені дуже добре: 1) що якщо ви скомпілюєте декларацію C-структури в C ++, те, що ви отримаєте, має бути еквівалентним тому, що ви мали в C. 2) POD потребуватиме / використовуватиме лише статичні (не динамічна) ініціалізація.

C ++ 0x / 11 повністю (майже) повністю відмовляється від позначення "POD" на користь "тривіального" та "стандартного макета". Стандартний макет призначений для фіксації першого задуму - створення чогось із макетом, таким же, як ви отримали б у C. Trivial призначений для захоплення підтримки статичної ініціалізації.

Оскільки new Tпроти new T()угод з ініціалізацією, ви, мабуть, хочете is_trivial.

Я не впевнений у необхідності магії компілятора. Моя негайна реакція була б, мабуть, так, але, знаючи деякі речі, які люди робили з TMP, я важко переконуюсь, що хтось теж не міг цього зробити ...

Редагувати: для прикладів, можливо, найкраще просто процитувати приклади з N3290:

struct N { // neither trivial nor standard-layout
   int i;
   int j;
    virtual ~N();
};

struct T { // trivial but not standard-layout
    int i;
private:
    int j;
};

struct SL { // standard-layout but not trivial
    int i;
    int j;
    ~SL();
};

struct POD { // both trivial and standard-layout
    int i;
    int j;
};

Як ви, безсумнівно, здогадаєтесь, PODце також структура POD.


1
Так trivial + standard layout = PODзавжди тримається?
fredoverflow

1
@FredOverflow: так, з умовою, що він перехідний, тому всі (нестатичні) члени повинні бути тривіальними + стандартний макет.
Джеррі Коффін,

@JerryCoffin, можливо, варто згадати суцільний макет пам'яті тривіальних типів, оскільки це досить важлива властивість
awdz9nld

8

Для типів POD new T()- це ініціалізація значення (ініціалізує значення всіх членів) і new Tне ініціалізує члени (ініціалізація за замовчуванням). Відмінності між різними формами ініціалізації див. У цьому питанні . Підсумок: вам потрібно is_pod.


0

Макет - це спосіб розташування членів об’єкта класу, структури або об’єднання в пам’яті. Це може бути суперечливим чи ні. Досить часто мова вказує макет, але якщо є щось на зразок віртуальної функції, віртуального базового класу тощо, то компілятор може вільно вибирати макет, і це може бути не суцільним. Це призводить до кількох проблем, через які ми не можемо належним чином серіалізувати об'єкт або передати його програмам, написаним іншими мовами, як-от C, або таким функціям, як memcopy, оскільки ми не можемо надійно скопіювати дані, які перебувають не в сусідніх місцях.

Щоб дозволити компіляторам та програмам c ++ підтримувати вищезазначені операції, c ++ представив 3 категорії для простих структур та класів.

Тривіальний

Клас або структура є тривіальними, якщо вони відповідають правилам:

  • відсутність віртуальної функції або віртуального базового класу
  • відсутність визначеного користувачем конструктора / оператора / деструктора
  • базовий клас повинен бути тривіальним
  • всі учасники класу повинні бути дріб’язковими

Якщо клас є тривіальним, то його макет є суперечливим, але може бути відповідно заповнення, і компілятор може вільно вибирати порядок членів у макеті. Тому, хоча ми можемо скопіювати об’єкт, це не є надійним, якщо ми скопіюємо цей об’єкт до програми C. Ми можемо мати різні специфікатори доступу в одному і тому ж класі, і якщо ми використовуємо параметризований конструктор, ми, очевидно, маємо вказати конструктор за замовчуванням. Але якщо ви хочете зберегти клас тривіальним, вам слід явно зробити конструктор за замовчуванням. Конструктори повинні бути загальнодоступними.

Стандартний макет

  • Немає віртуальних функцій і віртуального базового класу
  • Усі нестатичні члени повинні мати однакові специфікатори доступу
  • Усі нестатичні члени повинні мати стандартний макет
  • Усі базові класи повинні мати стандартний макет
  • Усі члени базового класу повинні бути статичними
  • Тип базового класу та першого нестатичного члена класу не повинні бути однаковими

Стандартний макет чітко визначений, і його можна надійно скопіювати та передати відповідним чином програмам C. Також стандартні функції компонування можуть мати визначені користувачем спеціальні функції-члени, такі як конструктор та деструктор.

POD (звичайні старі дані)

Якщо клас або структура є як тривіальним, так і стандартним макетом, тоді він називається POD.Кожний член зберігається в порядку, вказаному при оголошенні об'єкта. Класи POD повинні мати нестатичні члени даних POD. Класи POD можна копіювати або надійно передавати програмам C.

Програма C ++ із класом, який є тривіальним, стандартним макетом і, отже, POD.

#include<iostream>
#include<type_traits>
class xyz
{
public:
    int a;
    int b;
    xyz() = default;
    xyz(int x, int y) :a(x), b(y) {}
};
int main() {
    std::cout << std::is_trivial<xyz>() << std::endl;//true
    std::cout << std::is_standard_layout<xyz>() << std::endl;//true
    std::cout << std::is_pod<xyz>() << std::endl;//true
}

Літеральні типи

Для буквеного типу макет можна визначити під час компіляції. Приклади буквених типів порожні, скалярні типи, такі як int, float тощо, посилання, масиви void, скалярні типи або посилання та клас A, який має тривіальний деструктор, і один або кілька конструкторів constexpr, які не є конструкторами переміщення або копіювання. Крім того, усі його нестатичні члени даних та базові класи повинні бути буквальними типами та не мінливими


Це майже з docs.microsoft.com/en-us/cpp/cpp/… , чи буде простіше просто вставити URL-адресу?
r0ng
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.