【问题标题】:Is there any safe way to derive the offset of a T inside a std::optional<T>?有什么安全的方法可以在 std::optional<T> 中导出 T 的偏移量吗?
【发布时间】:2022-01-18 22:20:39
【问题描述】:

给定std::optional&lt;T&gt;,是否可以从T 的地址推导出std::optional&lt;T&gt; 的地址?

可能的实现:

template<typename T>
struct myoptional
{       static std::size_t getOffset(void)
        {       static const myoptional<T> s(std::inplace());
                return reinterpret_cast<const char*>(&s.value())
                       - reinterpret_cast<const char*>(&s);
        };
};

【问题讨论】:

  • T的地址是什么意思? T 是一种类型。
  • std::optional&lt;int&gt; i = 5; auto ao = &amp;i; auto ai = &amp;*i;
  • 即使你得到了这个偏移量,在实践中你可能没有用这个信息做任何有用的事情。这很可能是 XY 问题。您应该询问您正在尝试解决的问题,而不是询问您尝试过的解决方案。
  • @MichaelChourdakis 是 T 类型对象的地址,大概?还有什么意思?

标签: c++ stl stdoptional addressof


【解决方案1】:

未指定在其存储空间std::optional 中存储对象的确切位置。如果您假设对于同一类型T,对象的位置始终相同,您可以(见下文)使用所示方法通过对象表示获得偏移量。

但是,即使您知道对象的偏移量,您仍然无法从指向T 对象的指针中获得指向std::optional&lt;T&gt; 的可用指针。您需要 std::launder 生成的指针才能使其可用,只有在 sizeof(std::optional&lt;T&gt;) &lt;= sizeof(T) 时才允许这样做,这似乎不太可能/不可能。 (否则它将使以前无法访问的字节在术语 reachable 的含义中可以访问,如std::launder 的先决条件,请参阅https://en.cppreference.com/w/cpp/utility/launder


目前尚不清楚标准是否允许使用reinterpret_cast 和指针算法。该标准在这方面存在一些未解决的缺陷。

你可以做的或者(据我所知)不应该有未定义的行为是将std::optional&lt;T&gt;unionunsigned char[sizeof(std::optional&lt;T&gt;)]一起使用,而不是使用指针差异,你然后可以在循环中使用加法和指针比较来查找字符数组中与T 值的地址匹配的偏移量。参见例如this answer

【讨论】:

  • @FrançoisAndrieux 如果sizeof(std::optional&lt;T&gt;) &gt; sizeof(T) 则指向T 对象的指针将无法到达std::optional&lt;T&gt; 对象占用的存储空间中的某些字节。因此试图从T*std::optional&lt;T&gt;* 是不可能的。 (这是 OP 在问题正文中询问的方向。)
  • 对象表示上的指针算术问题是当前的语言缺陷。意图是应该允许,但措辞实际上并不支持它。
  • @FrançoisAndrieux 嗯,它不能更小,因为它被指定为在其内部为T 对象提供存储。
  • @FrançoisAndrieux 我希望我在回答中提到了你的 cmets。关于对象表示,我不清楚它是否应该以这种方式工作。问题是,如果允许显示的转换并导致指向同一数组元素的指针(std::optional&lt;T&gt; 对象的对象表示),这是允许指针算术所必需的,那么这种转换将有效地规避std::launder 可达性要求。您始终可以先转换为 char*/unsigned char*
猜你喜欢
  • 2017-05-14
  • 2018-03-22
  • 2021-11-21
  • 2013-07-04
  • 2014-06-24
  • 2014-06-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多