当前位置: 首页 > 知识库问答 >
问题:

什么时候我们应该为' std::unordered_set '提供我们自己的散列函数

徐昕
2023-03-14

当我编译以下代码时,我看到了与哈希相关的错误。

int F_no_meaningA(unordered_set<vector<int>>& setVec, vector<int>& vec) 
{
    setVec.insert(vec);
    return 1;
}

int main()
{
  vector<int> W{2, 3, 7}; 
  unordered_set<vector<int>> setVec; 
}

$ g++ --version
g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3

$ g++ $1.cpp -o $1 -g -Wall -Weffc++ -pedantic -std=c++0x

/tmp/ccCQFQ4N.o: 在函数“标准::__detail::_Hash_code_base

,标准::矢量

然后,我介绍了下面自己的Hash,问题就解决了。

问题 1

struct HashVector : unary_function<vector<int>, vector<int>::size_type> {
  vector<int>::size_type operator()(const vector<int>& vec) const {
    vector<int>::size_type sum = 0;
    for(int i : vec) {
      sum = sum*37 + hash<int>()(i);
    }
    return sum;
  }
};

int F_no_meaningB(unordered_set<vector<int>, HashVector>& setVec, vector<int>& vec) 
{
    setVec.insert(vec);
    return 1;
}

int main()
{
  vector<int> W{2, 3, 7}; 
  unordered_set<vector<int>, HashVector> setVec; 
}

警告:基类“结构”std::unary_function,无符号整型

问题2

非常感谢。

共有2个答案

商飞航
2023-03-14

什么时候应该为std::unordered_set提供自己的Hash?

该标准只需要有限数量的专门化,主要用于基元类型。这是因为这些基本类型具有实现可以提供的一些合理的默认“一刀切”哈希函数。更复杂的类型,例如自定义类型或容器,没有明显甚至合理的默认哈希,因此,您需要提供自己的哈希。如果不支持您的值类型,则必须为其提供哈希函数实现。

此外,提供自己的哈希函数的另一个原因是,您对unordered_set中值的分布有一些额外的专业知识。哈希表的性能对于哈希函数相对于表中存储的值的分布的适用性非常敏感。这是一个更完整的解释。标准默认值只是一种一刀切的解决方案,这意味着它既简单又方便,但几乎总是次优。

为什么g抱怨带有上述警告的struct HashVector?

这主要是应用与经典面向对象编程最相关的警告(使用基类作为派生类的动态多态接口)。在这种情况下,不将析构函数定义为虚拟的是一个非常严重的错误(这允许从基类实例中正确地析构派生类(例如,< code > delete base _ ptr)。正如Mike所建议的,这是因为启用了< code>-Weffc (它主要应用新手级别的经典OOP风格的警告消息)。然而,在您的代码中,继承是在泛型编程的上下文中使用的,在泛型编程中,继承以非常不同的方式使用(主要是用一些基础的属性和特征来灌输一个类)。在这种情况下,基类没有虚析构函数不是问题,因为它不打算用于动态多态设置,而是用于静态多态设置。

另请注意,std::unary_function(及其亲属)在最新标准(C 11)中已被弃用。这是因为最新标准提供了对类型自省的增强(使用

方弘
2023-03-14

何时应该为std::unordered_set提供自己的Hash?

当你使用的类型没有标准库提供的散列时。例如,它没有为标准容器提供散列函数,包括< code>vector

为什么g抱怨带有上述警告的struct HashVector?

因为您已经使用了-Weffc请求一个(稍微过于热情)警告,以便在您从没有虚拟析构函数的类继承时告诉您。对于继承的大多数用途(即多态性),您不希望这样做。然而,在这种情况下,继承只是被用来(或者,有人可能会说,被滥用了)向类中注入一些定义,因此警告并不表示有问题。

不推荐使用std::unary_function之类的类,因此最好的解决方案是根本不从中继承。

 类似资料:
  • 问题内容: 我在ORM上还很新。我刚刚开始阅读有关使用Hibernate的Java Persistence API的书籍和文档。 我只是想知道,关闭EntityManagerFactory与jdbc数据库连接关闭类似吗? 我们是否应该在每次持久/更新/删除后关闭它?如果我们不关闭它,数据库连接会保持打开状态吗? 问题答案: 我只是想知道,关闭与jdbc数据库连接关闭类似吗? 这并非完全正确,但关闭

  • 问题内容: 我正在使用’multiprocess.Pool.imap_unordered’如下 我需要打电话或之后的for循环? 问题答案: 不,您没有,但是如果您不再使用游泳池,那可能是个好主意。 Tim Peters在此SO帖子中致电或致电的理由很明确: 至于Pool.close(),您应该在永远不会将更多工作提交给Pool实例的情况下(且仅在)进行调用。因此,通常在主程序的可并行化部分完成时

  • 问题内容: 面试官问我: 什么是Observer,什么Observable时候应该使用它们? 我并不了解这些术语,因此当我回到家并开始使用GoogleObserver和Google搜索时Observable,从不同的资源中发现了一些要点: 1)Observable是一个类,Observer是一个接口。 2)Observable该类维护一个Observers的列表。 3)当一个Observable对

  • 我们应该在什么时候选择抛出一个异常? 我们可以在try catch中捕获此异常。 在哪种情况下,我们选择使用投掷而不是立即接球?是否与设计模式相关?

  • 问题内容: 我正在学习React js( 如果是ii App.js模块),我必须导入React,因为 render() 方法用于将JSX转换为dom元素,而在Person.js中,我们正在创建箭头函数,然后将其导出以便它可以被导入并在App模块的render函数中使用,就像我们在React中导入的App模块一样,它将在模块person中转换JSX并在DOM上渲染,但是当我们在Person中删除以下

  • 从外观上看-似乎创建了一个对象的克隆。如果是这样,那么对于实现可克隆接口(只有不可变对象是新的,因为可变对象有引用复制)的关注,哪一个是最好的,为什么? 我昨天实现了克隆,然后意识到我必须为非字符串/首字母元素提供自己的修改。然后我被告知我现在正在使用的。这两个实现似乎都提供了类似的功能。 谢谢