Если класс T
имеет требование выравнивания, такое как указано alignas
ключевое слово, являются std::optional<T>
а также boost::optional<T>
гарантированно соблюдать указанное выравнивание?
Если бы они были просто классами-обертками для T
объект и bool initialized
то они автоматически выровняют свои T
член по мере необходимости, но стандартная и расширенная документация утверждают, что они не могут содержать объект и хорошо справляются с дорогостоящими объектами. Из этого я понимаю, что они не просто содержат T
, Скорее, они, кажется, выделяют буфер, на котором T
построен или разрушен вручную. Поэтому язык C ++ не будет автоматически выравнивать буфер, потому что он не имеет типа T
,
Ну действуй std::optional<T>
а также boost::optional<T>
правильно выровнять их удалось T
объект? Они также обеспечивают optional<T>::operator new
а также optional<T>::operator new[]
что уважать требование выравнивания?
Соответствующая реализация std :: option должен соблюдать требования выравнивания его value_type
согласно проекту стандарта C ++ 17:
23.6.3 Шаблон класса необязательно [опционально.опционально]
(…)
Содержимое значение должно быть выделено в области дополнительного хранилища, соответствующим образом выровненной для типа Т.
Разработчик может использовать объединение, потенциально содержащее значение в качестве члена, обеспечивая правильное выравнивание.
Как уже упоминал Томас, когда я искал его, boost :: option обеспечивает правильное выравнивание с помощью aligned_storage<T>
В реализации GNU C ++, std::optional
происходит от _Optional_Base<_Tp>
который в свою очередь содержит _Optional_payload<_Tp>
, Это шаблон с несколькими специализациями, каждая из которых содержит следующие члены:
using _Stored_type = remove_const_t<_Tp>;
struct _Empty_byte { };
union {
_Empty_byte _M_empty;
_Stored_type _M_payload;
};
bool _M_engaged = false;
Как видите, _M_payload
на самом деле строго типизирован, поэтому любые атрибуты выравнивания должны переноситься должным образом в этой реализации.
Реализация Boost не использует объединение. Вместо, boost::optional<T>
происходит от optional_base<T>
, который просто содержит:
typedef aligned_storage<T> storage_type ;
bool m_initialized ;
storage_type m_storage ;
Имя aligned_storage
это ключ; документы не упоминайте, что второй аргумент шаблона является необязательным и по умолчанию равен -1, что означает boost::detail::max_align
, что означает использование выравнивания объединяющего типа, содержащего набор примитивных типов длиной до 128 бит. Так что (из краткого прочтения) Boost выглядит немного более пессимистично, чем GNU, но также выровняет ваше выравнивание.