如何在 c++ 中计算对象的哈希/校验和/指纹?
How can I calculate a hash/checksum/fingerprint of an object in c++?
如何在c++ 中计算对象的哈希/校验和/指纹?
要求:
该函数必须是"单射"(*(。换句话说,不应该有两个不同的输入对象,它们返回相同的哈希/校验和/指纹。
背景:
我正在尝试提出一个简单的模式来检查实体对象自构建以来是否已更改。(为了知道数据库中需要更新哪些对象(。
请注意,我特别不想在我的 setter 或其他任何地方将对象标记为已更改。
我正在考虑以下模式:简而言之,每个应该持久化的实体对象都有一个成员函数"bool is_changed(("。在此上下文中,"已更改"表示自调用对象的构造函数以来已更改。
注意:我这样做的动机是避免将对象标记为干净/脏或按成员比较进行成员比较时附带的样板代码。换句话说,降低人为错误的风险。
(警告:前面是 psudo c++ 代码。我还没有尝试编译它(。
class Foo {
private:
std::string my_string;
// Assume the "fingerprint" is of type long.
long original_fingerprint;
long current_fingerprint()
{
// *** Suggestions on which algorithm to use here? ***
}
public:
Foo(const std::string& my_string) :
my_string(my_string)
{
original_fingerprint = current_fingerprint();
}
bool is_changed() const
{
// If new calculation of fingerprint is different from the one
// calculated in the constructor, then the object has
// been changed in some way.
return current_fingerprint() != original_fingerprint;
}
void set_my_string(const std::string& new_string)
{
my_string = new_string;
}
}
void client_code()
{
auto foo = Foo("Initial string");
// should now return **false** because
// the object has not yet been changed:
foo.is_changed();
foo.set_my_string("Changed string");
// should now return **true** because
// the object has been changed:
foo.is_changed();
}
(*( 在实践中,不一定在理论上(就像 uuid 在理论上不是唯一的(。
这样的函数不存在,至少在您请求的上下文中不存在。
STL 为基本类型 (std::hash( 提供哈希函数,您可以使用这些函数通过任何合理的哈希算法为对象实现哈希函数。
但是,您似乎正在寻找一个注入函数,这会导致问题。本质上,要有一个单射函数,必须有一个大于或等于你正在考虑的对象大小的输出,因为否则(根据鸽子洞原理(将有两个输入给出相同的输出。鉴于此,最明智的选择是直接将对象与某种参考对象进行比较。
您可以使用 Boost 的 CRC32 算法。向它提供要校验和的数据的内存位置。为此可以使用哈希,但哈希是加密函数,旨在防止故意数据损坏,速度较慢。CRC表现更好。
对于此示例,我已将另一个数据成员添加到Foo
:
int my_integer;
这就是您将my_string
和my_integer
校验和的方式:
#include <boost/crc.hpp>
// ...
long current_fingerprint()
{
boost::crc_32_type crc32;
crc32.process_bytes(my_string.data(), my_string.length());
crc32.process_bytes(&my_integer, sizeof(my_integer));
return crc32.checksum();
}
但是,现在我们留下了两个对象具有相同指纹的问题,如果my_string
和my_integer
相等。为了解决这个问题,我们应该在CRC中包含对象的地址,因为C++保证不同的对象将具有不同的地址。
有人会认为我们可以使用:
process_bytes(&this, sizeof(this));
这样做,但我们不能,因为this
是一个右值,因此我们不能获取它的地址。所以我们需要将地址存储在一个变量中:
long current_fingerprint()
{
boost::crc_32_type crc32;
void* this_ptr = this;
crc32.process_bytes(&this_ptr, sizeof(this_ptr));
crc32.process_bytes(my_string.data(), my_string.length());
crc32.process_bytes(&my_integer, sizeof(my_integer));
return crc32.checksum();
}
- 如何用尽可能少的数据将数据缓冲区计算为零校验和值
- 计算校验和的逐位运算符
- 如何从存储在 QByteArray 中的十六进制值计算校验和
- 如何在 c++ 中计算对象的哈希/校验和/指纹?
- C++文件传输的校验和算法
- 如何从 IP 校验和字段中计算十六进制值
- 计算句子的校验和(XOR)(由不同变量/类型的组合形成)
- 目录校验和
- 编译后如何计算某些二进制功能(或基本块)的校验和
- 哈希表打印和插入功能
- PMS5003带有ESP8266-许多校验和错误
- 未正确的校验和释放对象 - 打印时错误
- 将C++校验和函数转换为 Java
- 确定是否使用boost.asio计算UDP校验和
- 校验和CRC 16从C 到Java
- 不同的CRC32校验和同一文件
- 哈希函数-截断和除法
- 在C++中实现哈希表(插入和延迟删除)
- Qt,tcp/ip通信校验和
- 正在计算ICMP数据包校验和