首页 > 解决方案 > 使用 mutable 允许修改 unordered_set 中的对象

问题描述

请考虑以下代码

#include <iostream>
#include <unordered_set>

struct MyStruct
{
    int x, y;
    double mutable z;

    MyStruct(int x, int y)
        : x{ x }, y{ y }, z{ 0.0 }
    {
    }
};

struct MyStructHash
{
    inline size_t operator()(MyStruct const &s) const
    {
        size_t ret = s.x;
        ret *= 2654435761U;
        return ret ^ s.y;
    }
};

struct MyStructEqual
{
    inline bool operator()(MyStruct const &s1, MyStruct const &s2) const
    {
        return s1.x == s2.x && s1.y == s2.y;
    }
};

int main()
{
    std::unordered_set<MyStruct, MyStructHash, MyStructEqual> set;
    auto pair = set.emplace(100, 200);

    if (pair.second)
        pair.first->z = 300.0;

    std::cout << set.begin()->z;
}

我正在使用mutable允许修改z. MyStruct我想知道这是否可行且合法,因为该集合是 a) 无序 b) 我不z用于散列或相等?

标签: c++mutableunordered-set

解决方案


我会说这是“可变”关键字的完美使用。

mutable 关键字用于标记不属于类“状态”的成员(即它们是某种形式的缓存或中间值,不代表对象的逻辑状态)。

您的相等运算符(以及其他比较器(或任何序列化数据的函数)(或生成哈希的函数))定义对象的状态。您的相等比较器在检查对象的逻辑状态时不使用成员“z”,因此成员“z”不是类状态的一部分,因此无法使用“可变”访问器。

现在这么说。我确实认为以这种方式编写代码非常脆弱。类中没有任何东西可以阻止未来的维护者不小心使 z 成为类状态的一部分(即将它添加到散列函数中),从而打破在std::unordered_set<>. 因此,您应该非常明智地使用它,并花费大量时间编写注释和单元测试以确保维护前提条件。

我还将研究“@Andriy Tylychko”关于将类分解为 const 部分和 value 部分的评论,以便您可以将其用作std::unordered_map.


推荐阅读