【问题标题】:Is the address of a std::optional's value stable?std::optional 值的地址是否稳定?
【发布时间】:2018-02-03 19:11:54
【问题描述】:

假设我有一个std::optional<T>。我多次重置并分配该值。对于给定的可选项,值的地址(如果存在)是否始终相同?

换句话说:

#include <cassert>
#include <optional>
#include <string>

template<typename T>
auto test()
{
    auto opt = std::optional<T>{T{}};
    auto* ptr = &*opt;

    opt.reset();
    opt = T{};

    assert(ptr == &*opt); // Can this assert fail?
}

int main()
{
    test<int>();
    test<double>();
    test<std::string>();
    // ...
}

标准是否保证值地址的稳定性?

【问题讨论】:

  • 标准相关部分:eel.is/c++draft/optional
  • 我没有看到任何需要对象保持在同一位置的东西,也就是说,似乎符合要求的实现可能具有sizeof(std::optional&lt;T&gt;) &gt;= 2*sizeof(T) 并移动对象的位置。但是没有一个理智的实现会这样做
  • @Justin 感谢您的链接!实际上,我想在某处存储指向该值的指针(C 库需要我的值的地址)。当 C 库访问指针时,我可以确保可选项确实具有价值。 “没有理智的实施”说得很好:-)
  • 这不是在对象的生命周期结束后检查其地址吗?

标签: c++ language-lawyer std c++17


【解决方案1】:

标准是否保证值地址的稳定性?

在我看来,地址是否稳定是未指定

正式地,标准只保证std::optional中包含的对象没有动态分配,并且包含对象存储为std::optional的一部分:

23.6.3 类模板可选[optional.optional]

任何给定时间的 optional 实例要么包含一个值 或不包含值。 当可选的实例包含 一个值,它意味着一个 T 类型的对象,称为 可选对象的包含值,在存储中分配 可选对象。不允许使用实现 额外的存储,例如动态内存,以分配其包含的 价值。包含的值应分配在 为 T 类型适当对齐的可选存储。 type optional 是根据上下文转换为 bool 的,转换 如果对象包含值,则返回 true;否则转换 返回 false。

实际的存储机制是由特定的实现定义的,因此,地址可能会改变。

然而,在实践中,实现将使用类似aligned_storage(参见boost implementation)或union(如gcc does)和保持包含对象的地址不变。

【讨论】:

  • 顺便说一句,由于std::optionalconstexpr 要求,union 是唯一可能的实现(当然,除非有魔法)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-26
  • 1970-01-01
  • 2022-12-22
  • 1970-01-01
  • 2022-01-04
  • 2021-09-05
  • 1970-01-01
相关资源
最近更新 更多