繁体   English   中英

我可以将 POD C-Array 的某些字节范围重新解释为 std::array<char,n> ?</char,n>

[英]Can I reinterpret_cast some byte range of a POD C-Array to std::array<char,N>?

我想使用长字节数组s固定连续字节作为std::map<std::array<char,N>,int>中的键。 我可以通过将s子数组重新解释为std::array<char,N>来做到这一点而不进行复制吗?

这是一个最小的例子:

#include <map>
int main() {
    std::map<std::array<char,10>,int> m;
    const char* s="Some long contiguous data";

    // reinterpret some contiguous 10 bytes of s as std::array<char,10>
    // Is this UB or valid? 
    const std::array<char,10>& key=*reinterpret_cast<const std::array<char,10>*>(s+5);

    m[key]=1;
}

我会说是的,因为char是一种不需要 alignment 到特定地址的 POD 类型(与更大的 POD 类型相比,请参阅https://stackoverflow.com/a/32590117/6212870 )。 因此,只要覆盖的字节仍然是s的子范围,即只要我确保没有缓冲区溢出,就可以从每个地址开始reinterpret_cast转换为std::array<char,N>

我真的可以这样做reinterpret_cast还是 UB?

编辑:在评论中,人们正确地指出了这样一个事实,即我无法确定对于std::array<char,10> arr它认为(void*)&arr==(void*)&arr[0]由于填充std::array模板 class 的内部 c 数组数据成员的可能性,即使这通常不应该是这种情况,特别是因为我们正在考虑一个char POD 数组。 所以我更新了我的问题:

当我通过static_assert检查确实没有填充时,我可以像上面那样依赖reinterpret_cast吗? 当然,代码不会再在有填充的编译器/平台组合上编译,所以我不会使用这种方法。 但我想知道:除了填充之外还有其他问题吗? 或者代码是否通过static_assert检查有效?

不——无论该类型的布局如何,该地址都没有std::array<char,10>类型的object char的特殊规则不适用于恰好具有char子对象的类型。)与往常一样,行为未定义的不是reinterpret_cast本身,而是当将其用作map键时通过该非对象进行的访问. (在这种情况下,您可以做的只是将其转换回真实类型,用于需要固定指针类型但实际上不使用 object 的类 C 接口。)

这种访问当然也涉及副本 如果您的目标是完全避免复制,只需制作一个

std::map<const char*,int,ten_cmp>

其中ten_cmp是一个仿函数类型,它比较从每个地址开始的 10 个字节(通过std::strncmpstd::string_view )。

如果您确实希望map拥有其密钥数据,只需将字符串中的std::memcpy转换为密钥即可; 编译器通常会认识到这种临时“缓冲区”不需要独立存在,并且实际上以您希望使用reinterpret_cast的方式从中读取。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM