[英]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::strncmp
或std::string_view
)。
如果您确实希望map
拥有其密钥数据,只需将字符串中的std::memcpy
转换为密钥即可; 编译器通常会认识到这种临时“缓冲区”不需要独立存在,并且实际上以您希望使用reinterpret_cast
的方式从源中读取。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.