Является ли std:: array гарантированно POD, если T POD?


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

  1. типы стручков. например, Маймем.Читать (Некоторый Адрес);
  2. типы строк. например, Маймем.Read>(SomeAddress); (на самом деле это не считывание строки C++, это считывание строки в стиле C и преобразование ее в строку C++.)
  3. векторные типы. например, Маймем.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::array если T-POD, то std::array-POD. (Что означает, что я могу просто использовать перегрузку 1, и это работает.)

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

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

Спасибо

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

3 16

3 ответа:

§23.3.1:

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

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

Или, чтобы быть анальным, можно сравнить маркеры §9/5 (определение тривиального класс) 9/6 (определение типовой формы стандартов) и 9/9 (объединение предыдущих требований в стручок) с требованиями раздела 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:

9 классы

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

[Курсив мой]

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

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


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

И хотя я не думаю, что есть какие-либо гарантии о Поднесности 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 специальных функций-членов для агрегатов.