Является ли std :: arrayгарантированно будет POD, если T является POD? - PullRequest
17 голосов
/ 09 сентября 2010

В настоящее время я пишу библиотеку для редактирования памяти C ++, а для API чтения / записи я использую черты типа (std :: is_pod, std :: is_same) и boost :: enable_if для обеспечения 3 перегрузок:

  1. Типы POD.например, MyMem.Read (SomeAddress);
  2. Типы строк.например, MyMem.Read> (SomeAddress);(Это на самом деле не считывает строку C ++, она считывает строку в стиле C и преобразует ее в строку C ++.)
  3. Векторные типы.например, MyMem.Read> (SomeAddress, NumElem);(На самом деле это не считывает вектор, скорее он считывает массив в стиле C и преобразует его в вектор.)

Перегрузки 2 и 3 являются просто «обертками» вокруг перегрузки 1.(Так что, если вы читаете std :: vector или std :: basic_string, а T не является POD, он потерпит неудачу, как и должно быть.)

Недавно я хотел использовать std :: array для множествачитает и пишет, потому что я знал размер данных, которые я хотел прочитать и записать во время компиляции (я писал оболочку для формата PE).

Я написал код для использования std :: array,и затем намеревался добавить еще одну перегрузку для обнаружения и обработки типов std :: array, но я случайно нажал на compile и, к моему удивлению, это сработало!

В настоящее время я использую MSVC 10, и оказалось, что для std:: массив, если T - POD, тогда std :: array - это POD.(Это означает, что я могу просто использовать перегрузку 1, и она работает.)

Мой вопрос заключается в том, гарантируется ли это стандартом C ++ или оставлено на усмотрение реализации.

Я знаю, что могу проверитьЯ сам по себе стандарт, но я не доверяю себе настолько, насколько доверяю некоторым языковым адвокатам на этом сайте, поэтому я подумал, что было бы лучше получить «второе мнение».;)

Спасибо

PS Код доступен здесь (это библиотека только для заголовков): http://code.google.com/p/hadesmem/source/browse/trunk/HadesMem-v2/Hades-Memory/Hades-Memory/MemoryMgr.h#86

Ответы [ 3 ]

11 голосов
/ 09 сентября 2010

§23.3.1:

Массив - это агрегат (8.5.1), который можно инициализировать с помощью синтаксиса array a<T, N> = { initializer-list }; где initializer-list - разделенный запятыми список до N элементов, типы которых могут быть преобразованы в T.

В C ++ 03 POD был определен в терминах агрегата: класс, в котором каждый подобъект является собственным или агрегат является POD. Таким образом, из-за обратной совместимости C ++ 0x std::array - это POD.

Или, чтобы быть анальным, можно сравнить пункты 9, 5 (определение тривиального класса) 9/6 (определение стандартного макета) и 9/9 (объединение предыдущих требований в POD) с 8,5. .1 / 1, который определяет агрегаты.

8.5.1:

Агрегат - это массив или класс (раздел 9) без предоставленных пользователем конструкторов (12.1), без инициалов-скобок или равных для нестатических элементов данных (9.2), без приватных или защищенных нестатических члены данных (статья 11), без базовых классов (статья 10) и без виртуальных функций (10.3).

Действительно, требования в разделе 9 охватывают array, если его тип элемента также является POD, а реализация не объявляет operator= или move внутри array в дополнение к спецификациям.

Быть действительно анальным, 17.5.2.2 говорит

  1. В целях изложения в разделах 18–30 и Приложении D не описываются конструкторы копирования / перемещения, операторы присваивания или (не виртуальные) деструкторы с той же очевидной семантикой, что и те, которые могут генерироваться по умолчанию (12.1, 12,4, 12,8).
  2. Не определено, предоставляет ли реализация явные определения для таких сигнатур функций-членов или для виртуальных деструкторов, которые могут генерироваться по умолчанию.

Примечание в псевдокоде для template class array равно

// No explicit construct/copy/destroy for aggregate type

Включает ли construct/copy/destroy operator= (назначение) или move? Наверное, так и должно быть, но я не думаю, что в самом строгом прочтении это так.

Обратите внимание, что это "влияет" не только на POD, но и на простоту копирования, как упоминает Йоханнес.

7 голосов
/ 09 сентября 2010

По определению POD:

9 Классы

9 Структура POD - это класс, который является одновременно тривиальным классом и стандартным классом макета и не имеет нестатических членов-данных Тип не POD структура, не POD объединение (или массив таких типов). Аналогично, объединение POD - это объединение, которое является одновременно тривиальным классом и стандартным классом макета и не имеет нестатических членов-данных типа не-POD структура, не-POD объединение (или массив таких типов). Класс POD - это класс, который является либо структурой POD, либо объединением POD.

[Выделение мое]

std::array удовлетворяет всем требованиям тривиального стандартного шаблона класса. Так что ответ на ваш вопрос - да.

1 голос
/ 09 сентября 2010

Potatoswatter обнаружил ошибку в моих выводах.C ++ явно позволяет реализации явно определять оператор присваивания «с такой же очевидной семантикой».Это сделает его нетривиально копируемым типом.Делая это сообществом вики ...


Мне кажется, вы не хотите тестировать против PODnes, но против тривиально копируемого , что гораздо меньше ограничений.Потому что именно так C ++ 0x ограничивает типы, которые можно использовать с memcpy и друзьями.

И хотя я не думаю, что есть какие-либо гарантии относительно PODness std::array, - это гарантии относительно тривиального копирования, как показано ниже (если яне получил ошибку в выводах).Как мы знаем, std::array является агрегатом, а агрегаты -

Агрегат - это массив или класс (раздел 9) без предоставленных пользователем конструкторов (12.1), без скобки или равенства- инициализаторы для нестатических элементов данных (9.2), без личных или защищенных нестатических элементов данных (раздел 11), без базовых классов (раздел 10) и без виртуальных функций (10.3).

Хотя тривиально копируемость определяется для класса, класс которого

  • не имеет нетривиальных конструкторов копирования (12.8),
  • не имеет нетривиальных конструкторов перемещения (12.8),
  • не имеет нетривиальных операторов назначения копирования (13.5.3, 12.8),
  • не имеет нетривиальных операторов назначения перемещения (13.5.3, 12.8) и
  • имеет тривиальный деструктор (12.4).

std::array не имеет деструктора (как говорится в комментарии в определении std::array).Похоже, что это не следует из определения агрегатных классов, хотя это и подтверждается в комментарии в определении класса std::array.

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

...