uni*_*ptr 5 c++ hash orm checksum
如何在 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();
}
Run Code Online (Sandbox Code Playgroud)
(*) 在实践中,不一定在理论上(就像 uuid 在理论上不是唯一的)。
您可以使用Boost 的 CRC32 算法。将您想要校验和的数据的内存位置提供给它。您可以为此使用散列,但散列是旨在防止故意数据损坏的加密函数,并且速度较慢。CRC 性能更好。
对于此示例,我添加了另一个数据成员Foo:
int my_integer;
Run Code Online (Sandbox Code Playgroud)
这就是对 和 进行校验的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();
}
Run Code Online (Sandbox Code Playgroud)
然而,现在我们剩下的问题是,如果my_string和my_integer相等,则两个对象具有相同的指纹。为了解决这个问题,我们应该在 CRC 中包含对象的地址,因为 C++ 保证不同的对象将具有不同的地址。
人们会认为我们可以使用:
process_bytes(&this, sizeof(this));
Run Code Online (Sandbox Code Playgroud)
这样做,但我们不能,因为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();
}
Run Code Online (Sandbox Code Playgroud)