【问题标题】:In C++20, can we pack together header and data objects and access the data from the header by offset?在 C++20 中,我们可以将 header 和 data 对象打包在一起,并通过偏移量从 header 中访问数据吗?
【发布时间】:2021-10-14 17:28:47
【问题描述】:
struct header
{
    int a1;
    int a2;
    // ...;

    std::byte * get_data_bytes()
    {
        return align_up<data>( // make sure alignment requirements are met
                    reinterpret_cast<std::byte *>(this) + sizeof(*this)); 
       // maybe std::launder around the reinterpret_cast (only) is needed?
    }

    data & get_data()
    {
        return *std::launder(reinterpret_cast<data *>(get_data_bytes()));
    }

    void use_data()
    {
        get_data().use();
    }
};

void example()
{
    alignas(header) std::byte storage[/* plenty of space*/]; 
    
    auto h = new (storage) header;
    new (h->get_data_bytes()) data;
    
    h->use_data(); // Does this eventually cause a UB?
}

如果没有 UB,这可能吗?如果没有,是否有替代方案? 要求是数据不是标头的子对象,并且有 没有指向标头数据的指针/引用,以避免额外的 间接性。这也许可以通过灵活的空数组实现,但我 不要认为这些在标准中。

【问题讨论】:

  • 你能再澄清一下data的类型要求吗?我认为你在这里绕着混叠违规跳舞。
  • @AndyG 我故意没有提供data 的任何细节,但可以从一个包含几个整数的普通类型开始讨论。
  • 这叫“射自己的脚”。获取结构的起始地址,添加您要访问它的项目的偏移量,使用 C-Style cast 将地址(指针)转换为您想要的。完全未定义的行为。请记住,您可能必须在偏移计算中考虑填充。
  • @CppNerd13373 AFAIK 不,问题是在一般意义上您正在尝试进行结构破解。问题是编译器可以通过sizeof 在数组中放置比对象实际需要的更多的填充。这意味着即使该对象有一个sizeof 12,它也可以对齐到 16 等。如果你好奇的话,上面有一个 CPPCon 视频
  • @ThomasMatthews 尽管这个例子看起来有人想在脚上开枪,但在与低级代码或硬件通信时,几乎所有地方都必须这样做。它通常被布置为最后带有空数组的结构,以便能够在您的标头对象之后访问任意数据。如果您确定这是未定义的行为,请您解释原因并提供替代方法吗?

标签: c++ c++20


【解决方案1】:

唯一甚至假设是 UB 是 reinterpret_cast&lt;std::byte *&gt;(this) 是否是指向数组中某个字节的指针。但是你可以std::launder它来确保它是。确实,对字节指针进行清洗非常有用,您可以为它们创建模板函数:

template<typename T>
std::byte *to_byte_ptr(T *ptr)
{
  return std::launder(reinterpret_cast<std::byte*>(ptr));
}

template<typename T>
T *from_byte_ptr(std::byte *ptr)
{
  return std::launder(reinterpret_cast<T*>(ptr));
}

其他一切都很好。您在字节数组提供的存储空间中创建了header,因此可以通过launder 访问std::byte 对象。由于这些std::byte 对象位于数组中,因此您可以对它们进行指针运算。虽然那些std::byte 对象实际上并不指向它们为其提供存储的对象,但如果您有一个与所需对象具有相同地址的指针,您可以launder 它检索指向该对象的指针。

【讨论】:

  • 这正是我的想法,所以感谢您给我这个见解。不管这听起来多么直观,我在标准中找不到信心告诉我在清洗后清洗 this 或 this+1 确实指向 std::byte 数组的数组元素。此外,在阅读清洗要求时,我对可达性要求感到困惑。你能指导我完成吗?
猜你喜欢
  • 2015-12-27
  • 2023-03-24
  • 2018-03-10
  • 1970-01-01
  • 1970-01-01
  • 2010-12-03
  • 1970-01-01
  • 2012-01-18
  • 2014-04-14
相关资源
最近更新 更多