对于结构,其中相等意味着每个数据成员的最大派生类型和字节相等,如果有的话,结构是否可以安全地作为字节数组进行哈希处理?
本文件
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3333.html
标题"将对象散列为字节数组"建议任何填充的结构都不能安全地散列为一个字节数组。
是否需要将结构安全地散列为字节数组的填充的显式测试?这还够吗?
如果是这样,下面的草图是否恰当地说明了该测试?
#include <cstddef>
#include <iostream>
struct A
{
int i;
float f;
char c;
};
// hashing would start at offs_i (possibly hopping over a v-table) and end at
// offs_c + sizeof(char)
int main()
{
const std::size_t size_A = sizeof(A);
const std::size_t size_int = sizeof(int);
const std::size_t size_float = sizeof(float);
const std::size_t size_char = sizeof(char);
const std::size_t offs_i = offsetof(A, i);
const std::size_t offs_f = offsetof(A, f);
const std::size_t offs_c = offsetof(A, c);
bool padded = false;
if (offs_f != size_int)
padded = true;
else if (offs_c != size_int + size_float)
padded = true;
std::cout << "padded? " << std::boolalpha << padded << std::endl;
}
如果一个结构有填充,有没有办法解决方法允许散列作为一个字节数组,例如将填充位置零?
&#34;安全&#34;这里的意思是两个结构,它们将相等的哈希值与相同的值进行比较。
答案 0 :(得分:4)
几乎没有。标准没有定义如何实现继承,例如使用vtable指针,因此无法保证两个具有相同最大派生类型的类将具有任何特定于实现的继承相关数据。
此外,由于它们不是POD,因此无法保证偏移效果或产生有意义的结果 - 我相信它实际上只是简单的UB。
长期和短期是,不要试图将结构视为字节数组,因为它们不是。
关于他在纸上的意图,它更可能是对一些狂热的“呃mah gerd表演”的让步!委员会中的狗而不是他想要做的事情。
答案 1 :(得分:2)
你引用的文章很多说明要求:
is_trivially_copyable<T>::value &&
is_standard_layout<T>::value &&
is_contiguous_layout<T>::value
对于struct本身和所有成员,必须递归执行。
前两个检查已经是标准库的一部分,您可以自己实现is_contiguous_layout<T>::value
。作为基础,它应足以将其成员的大小总和与结构本身的大小进行比较。我不认为,检查偏移实际上是必要的。
如果您的类型仅由整数类型组成,那么这应该适用于“通常的”平台(CHAR_BIT == 8
,2 - 补码)。但是,我不确定它是否也适用于bool和浮点数,因为我认为标准并没有强制要求变量值与其位表示之间的唯一双向映射。
编辑:我刚刚意识到你不能满足条件of same most derived type
,如果在派生类中没有添加任何成员,或者你比较两个恰好具有相同成员的不同类。因此,您必须单独考虑该类型。
答案 2 :(得分:0)
如果结构是POD,你应该能够在初始化时将整个结构的bzero或memcpy设置为0,然后作为字节数组进行散列应该没有问题,并且效率很高。