std :: unordered_set允许插入重复项

时间:2014-10-16 23:03:48

标签: c++ c++11 hash

我不理解正确的事情。我的印象是unordered_set不允许基于哈希值的重复元素。

我有一个结构,具有std :: hash的特化,看起来允许重复,虽然我已经手动检查了它

AddEdge ( const std::shared_ptr<Relation> relation, const std::shared_ptr<Concept> concept )
{
    auto edge = std::make_shared<Edge>( (Edge){ relation, concept } );
    auto res = _edges.insert ( edge );
    return res.second;
}

重载函数完全相同但反转参数

这是struct Edge的散列方式:

namespace std
{
    template<> struct hash<shared_ptr<Edge>>
    {
        size_t operator()( const shared_ptr<Edge> & ptr ) const
        {
            size_t from = 0;
            size_t to = 0;

            if ( auto node = std::dynamic_pointer_cast<Concept>( ptr->from ) )
                from = hash<shared_ptr<Concept>>()( node );

            else if ( auto node = std::dynamic_pointer_cast<Relation>( ptr->from ) )
                from = hash<shared_ptr<Relation>>()( node );

            if ( auto node = std::dynamic_pointer_cast<Concept>( ptr->to ) )
                 to = hash<shared_ptr<Concept>>()( node );

            else if ( auto node = std::dynamic_pointer_cast<Relation>( ptr->to ) )
                 to =  hash<shared_ptr<Relation>>()( node );

            return hash<size_t>()( from + to );
        }
    };
}

容器保存在:

std::unordered_set<std::shared_ptr<Edge>> _edges;

当我这样做时:

graph2->AddEdge( sea_node, is_node );
graph2->AddEdge( is_node, blue_node );

我明白了:

Edge [sea,is] hash = 10017731961838884781
Edge [is,blue] hash = 11178184051384786808

我第二次尝试完全一样,我得到相同的哈希值,但是,当我检查边缘时,我现在有4条边而不是2条。

我做错了什么?

编辑:课程概念&amp; Relation具有相同类型的哈希函数:

namespace std
{
    template<> struct hash<shared_ptr<Concept>>
    {
        size_t operator()( const shared_ptr<Concept> & ptr ) const
        {
            return hash<string>()( ptr->asToken()->value() ) + hash<int>()( ptr->TokenIndex() ) + hash<string>()( "Concept" );
        }
    };
}

更有意思的是,我添加Edges时的输出会生成相同的哈希值,但是会添加重复的Edge。

1 个答案:

答案 0 :(得分:9)

  

unordered_set将不允许基于哈希值的重复元素

不,unordered_set通过比较而不是那些值的哈希值来避免重复。
每个共享指针的“值”将会有所不同,因为它们引用了不同的对象。

您实际上可以通过将自己的函数作为KeyEqual的{​​{1}}模板参数来更改此行为:

unordered_set

如果template< class Key, class Hash = std::hash<Key>, // <-- you've been looking at this class KeyEqual = std::equal_to<Key>, // <-- instead of this class Allocator = std::allocator<Key> > class unordered_set; 中只允许一个具有给定哈希的值,则(a)您将无法添加任何真正导致哈希冲突的值,(b)完全不需要整个哈希冲突解决机制。