如何在 C++ 中计算对象的哈希/校验和/指纹?

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 在理论上不是唯一的)。

Nik*_* C. 2

您可以使用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_stringmy_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)