【问题标题】:C++: shared_ptr as unordered_set's keyC++:shared_ptr 作为 unordered_set 的键
【发布时间】:2011-06-19 19:51:37
【问题描述】:

考虑下面的代码

#include <boost/unordered_set.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>

int main()
{
    boost::unordered_set<int> s;
    s.insert(5);
    s.insert(5);
    // s.size() == 1 

    boost::unordered_set<boost::shared_ptr<int> > s2;
    s2.insert(boost::make_shared<int>(5));
    s2.insert(boost::make_shared<int>(5));
    // s2.size() == 2
}

问题是:为什么 s2 的大小是 2 而不是 1?我很确定它一定与哈希函数有关。我尝试查看 boost 文档并在没有运气的情况下使用哈希函数。

想法?

【问题讨论】:

    标签: boost shared-ptr hash-function unordered-set


    【解决方案1】:

    make_shared 分配一个新的int,并在其周围包裹一个shared_ptr。这意味着您的两个shared_ptr&lt;int&gt;s 指向不同的内存,并且由于您正在创建一个以指针值为键的哈希表,它们是不同的键。

    出于同样的原因,这将导致大小为 2:

    boost::unordered_set<int *> s3;
    s3.insert(new int(5));
    s3.insert(new int(5));
    assert(s3.size() == 2);
    

    在大多数情况下,您可以将shared_ptrs 视为指针,包括用于比较,但自动销毁除外。

    您可以定义自己的哈希函数和比较谓词,并将它们作为模板参数传递给unordered_map,不过:

    struct your_equality_predicate
        : std::binary_function<boost::shared_ptr<int>, boost::shared_ptr<int>, bool>
    {
        bool operator()(boost::shared_ptr<int> i1, boost::shared_ptr<int> i2) const {
            return *i1 == *i2;
        }
    };
    
    struct your_hash_function
        : std::unary_function<boost::shared_ptr<int>, std::size_t>
    {
        std::size_t operator()(boost::shared_ptr<int> x) const {
            return *x; // BAD hash function, replace with somethign better!
        }
    };
    
    boost::unordered_set<int, your_hash_function, your_equality_predicate> s4;
    

    但是,出于以下几个原因,这可能不是一个好主意:

    1. x != ys4[x]s4[y] 是相同的。
    2. 如果有人改变了哈希键所指向的值你的哈希值将被破坏!那就是:

      boost::shared_ptr<int> tmp(new int(42));
      s4[tmp] = 42;
      *tmp = 24; // UNDEFINED BEHAVIOR
      

    通常使用哈希函数,您希望密钥是不可变的;无论以后发生什么,它总是比较相同。如果您使用指针,您通常希望指针标识是匹配的,如extra_info_hash[&amp;some_object] = ...;无论some_object 的成员可能是什么,这通常都会映射到相同的哈希值。插入后键是可变的,实际上这样做太容易了,从而导致哈希中的未定义行为。

    【讨论】:

    • 好吧,当然。所以我仍然应该能够通过使用(智能)指针来实现相同的语义?这意味着通过以某种特定方式定义散列函数,大小将是 1 而不是 2。我该怎么做?
    【解决方案2】:

    请注意,在 Boost boost::shared_ptr 的默认 hash_value 是其布尔值 truefalse。 对于不是 NULL 的任何 shared_ptrhash_value 的计算结果为 1(一),如 (bool)shared_ptr == true

    换句话说,如果您使用的是 Boost 将哈希集降级为链表。

    这在 Boost 1.47.0 中已修复,请参阅 https://svn.boost.org/trac/boost/ticket/5216

    如果您使用std::shared_ptr,请定义您自己的哈希函数,或使用Boost >= 1.51.0 中的boost/functional/hash/extensions.hpp

    【讨论】:

      【解决方案3】:

      如您所见,插入s2 的两个对象是不同的。

      【讨论】:

        猜你喜欢
        • 2021-09-02
        • 1970-01-01
        • 2011-03-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-10-02
        • 2010-10-28
        • 2018-11-18
        相关资源
        最近更新 更多