Простая структура данных

Материал из Энциклопедия о программировании
Перейти к: навигация, поиск

Простая структура данных (англ. Plain old data, офиц. аббр. POD) в современных ЯП высок. ур. — тип данных, имеющий жёстко определённое расположение полей в памяти, не требующий ограничения доступа и автоматического управления. Переменные такого типа можно копировать простыми процедурами копирования участков памяти наподобие memcpy. Противоположность — управляемая структура данных.

Определение

Простую структуру данных проще всего определить от противного. Если компилятор скрытно от пользователя переставил поля местами, или при создании структуры данных скрытно вызывает конструктор, или при уничтожении структуры вызывает деструктор, или при копировании — особую процедуру копирования, то это управляемая, т.е. непростая, структура.

Преимущества простых структур данных

Простые структуры данных имеют 2 особенности.

Предсказуемое устройство в памяти

Компилятор может автоматически перестроить структуру данных по своему усмотрению – напр., изменить порядок полей. Подобная перестройка может серьёзно сэкономить память, но нарушает совместимость. В POD’ах такая оптимизация отключена.

Другими словами: типы, отмеченные как POD, устроены в памяти в точности так, как описал программист (возможно, с некоторым выравниванием). Поэтому только POD’ы можно использовать для связи между двумя библиотеками времени выполнения. В частности — для передачи данных из программы в программу, из плагина в плагин, для связи с кодом, написанным на др. ЯП. Чтобы быстро записать на накопитель сложный заголовок файла наподобие BMP, можно сформировать его в памяти, а затем записать одной командой — но структура данных, в которой формируем заголовок, также должна быть POD’ом.

Отсутствие управляющего кода

Это значит, что при появлении объекта не нужно вызывать конструктор, при копировании — операцию присваивания, а при уничтожении — деструктор. Это, в свою очередь, даёт след. преимущества:

  1. Статическая инициализация. Вместо того чтобы при запуске программы скрытно от программиста вызывать конструктор, POD’ы можно собрать ещё при компиляции программы.
  2. Тривиальное копирование функциями наподобие memcpy. Опять-таки, это важно для связи между программами: ведь менеджер памяти не должен заниматься управлением в той памяти, которая ему не принадлежит.
  3. Только простые типы могут находиться в union (в Pascal, соответственно, record/case).
  4. Функции с побочным эффектом наподобие GetLastError плохо совместимы с автоматически управляемыми типами.

ЯП с только простыми типами

ЯП, в которых все типы являются простыми:

В C++

В C++ POD определяется от противного. Тип данных является POD’ом, если:

  • у него нет конструктора, деструктора и копирующей операции присваивания (т.е. operator=, принимающего на входе тот же тип);
  • среди нестатических полей нет ссылок C++, не-POD’ов, private и protected;
  • нет виртуальных методов;
  • он ни от чего не унаследован.

По стандарту C++, простой тип данных устроен в точности так, как описано. Управляемую же структуру компилятор может реорганизовать так, как он сочтёт наиболее эффективным.

В C++11

«Предсказуемое устройство в памяти» и «отсутствие управляющего кода» — сходные, но разные свойства типа. Напр., структуру данных STRRET, которая в ОС Windows служит для передачи строк из одного менеджера памяти в другой, можно «обернуть» в управляющий код, но 2-ое св-во — предсказуемое устройство — остаётся. Поэтому концепция POD’ов в C++11 разделена на 3.

Класс является тривиальным, если у него тривиальны:

  • конструктор по-умолч. T();
  • конструктор копирования T(T&);
  • конструктор перемещения T(T&&); Отсюда следует, что у тривиального класса нет виртуальных методов и виртуального наследования.
  • деструктор ~T();
  • операция присваивания operator=(T&);
  • операция перемещения operator=(T&&).

Такие типы могут копироваться через memcpy.

Класс является типом со стандартным устройством, если:

  • все нестатические поля имеют одинаковые права доступа (все private, все protected или все public) и определены в одном классе.
  • нет виртуальных методов, виртуального наследования.
  • первое определённое поле не совпадает по типу ни с одним из родительских классов.

У таких типов предсказуемое устройство в памяти, их можно передавать в др. библиотеку времени выполнения.

Тогда POD — это тривиальный тип со стандартным устройством, все нестатические поля которого — POD’ы.

Для работы с константами, вычисляемыми при компиляции, и статической инициализации в C++11 есть более мягкое понятие — литеральный тип. А именно:

  • либо тривиальный конструктор по-умолч. T(), либо какой-нибудь конструктор (кроме конструктора копирования и перемещения) отмечен как constexpr;
  • конструктор копирования T(T&) тривиальный; Отсюда следует, что у литерального класса нет виртуальных методов и виртуального наследования.
  • конструктор перемещения T(T&&) тривиальный или запрещён;
  • тривиальный деструктор ~T();
  • унаследован от литеральных типов;
  • все его нестатические поля литеральные.

В Embarcadero Delphi

Простыми структурами данных считаются все типы, кроме:

  • новых строк неограниченной длины (AnsiString, WideString, UnicodeString). Впрочем, если не задевать скрытые управляющие поля, а работать только с данными, System.Copy использовать можно — не забывая, конечно, что несколько строк могут ссылаться на одну память и прежде надо вызвать функцию UniqueString;
  • интерфейсов COM;
  • динамических массивов;
  • типов, которые содержат один из этих 3-ёх;
  • новых объектов типа class. Впрочем, TObject, TButton и т.д. это указатели на объект и всегда являются простыми типами.

См. также

По теме «Простая структура данных» см. также сдед.: