【问题标题】:Do std::optional and boost::optional respect alignment restrictions of the managed object?std::optional 和 boost::optional 是否尊重托管对象的对齐限制?
【发布时间】:2018-02-12 18:28:56
【问题描述】:

如果类T 有对齐要求,例如由alignas 关键字指定的,那么std::optional<T>boost::optional<T> 是否保证遵守所述对齐?

如果它们只是 T 对象和 bool initialized 的包装类,那么它们将根据需要自动对齐其 T 成员,但标准和 boost 文档声明它们可以不保存任何对象并且处理得很好构造对象的成本很高。据我了解,它们不仅仅包含T。相反,他们似乎分配了一个缓冲区,T 在该缓冲区上手动构建或销毁。因此,C++ 语言不会自动对齐缓冲区,因为它不是T 类型。

那么,std::optional<T>boost::optional<T> 是否正确对齐其托管的 T 对象?他们是否还提供尊重对齐要求的optional<T>::operator newoptional<T>::operator new[]

【问题讨论】:

  • ............是的。
  • 答案不是显然是吗?我无法想象一个不尊重模板类型对齐的完整实现。
  • 他们为什么要提供operator new
  • 因为表达式new std::optional<T> 不受Tstd::optional<T>alignas 说明符的影响。

标签: c++ boost c++17 boost-optional stdoptional


【解决方案1】:

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

23.6.3 类模板可选[optional.optional]

(...) 包含的值应分配在与 T 类型适当对齐的可选存储区域中。

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

正如我在查找时 Thomas 已经提到的, boost::optional 确实通过使用 aligned_storage<T> 确保正确对齐

【讨论】:

  • 感谢您找到这个。 cppreference.com 没有提到任何关于对齐的内容,我认为它实际上没有被标准指定。为了完整起见,您可能想在帖子中提及第 23.6.3 段。
  • @patatahooligan:感谢您的反馈,我在答案中添加了标题。
【解决方案2】:

在 GNU C++ 实现中,std::optional 派生自 _Optional_Base<_Tp>,而 _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&lt;T&gt; 派生自 optional_base&lt;T&gt;,它只包含:

 typedef aligned_storage<T> storage_type ;
 bool m_initialized ;
 storage_type m_storage ;

aligned_storage 的名字是一个线索; docs 没有提到第二个模板参数是可选的,默认为 -1,这意味着 boost::detail::max_align,这意味着使用包含一堆长度为 128 位的原始类型的联合类型。所以(粗略阅读)Boost 似乎比 GNU 更悲观一点,但也会让你的对齐正确。

【讨论】:

  • 我猜boost版本的源代码已经足够了,但是std版本我不能依赖具体的实现。我需要标准的保证。
猜你喜欢
  • 1970-01-01
  • 2013-05-09
  • 2021-09-05
  • 2013-06-01
  • 2018-02-28
  • 1970-01-01
  • 2014-11-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多