std::可选和提升::可选是否尊重托管对象的对齐限制?

Do std::optional and boost::optional respect alignment restrictions of the managed object?

本文关键字:对象 对齐 是否 std      更新时间:2023-10-16

如果类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 newoptional<T>::operator new[]

根据 C++17 标准草案,符合 std::optional 的实现必须尊重其value_type的对齐要求:

23.6.3 类模板可选 [可选.可选]

(... 所包含的值应分配给与T型适当对齐的可选存储区域。

实现者可以使用可能包含值作为成员的联合,以确保正确对齐。

正如托马斯在我查找它时已经提到的那样,boost::optional 确实通过使用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::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更悲观一些,但也会让你的对齐正确。