3

考虑以下代码

#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 文档并在没有运气的情况下使用散列函数。

想法?

4

3 回答 3

8

make_shared分配一个新的int,并shared_ptr环绕它。这意味着您的两个shared_ptr<int>s 指向不同的 memory,并且由于您正在创建一个以指针值为键的哈希表,因此它们是不同的键。

出于同样的原因,这将导致大小为 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[&some_object] = ...; 这通常总是映射到相同的哈希值,无论some_object' 的成员可能是什么。由于插入后键是可变的,实际上这样做太容易了,从而导致散列中的未定义行为。

于 2011-06-19T19:55:48.410 回答
2

请注意,在 Boost <= 1.46.0 中, a 的默认hash_valueboost::shared_ptr是它的布尔值,true或者false. 对于任何shared_ptr不是 的NULLhash_value评估为 1(一),因为(bool)shared_ptr == true.

换句话说,如果您使用 Boost <= 1.46.0,则将哈希集降级为链表。

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

如果你正在使用std::shared_ptr,请定义你自己的哈希函数,或者使用boost/functional/hash/extensions.hppBoost >= 1.51.0

于 2012-08-25T13:18:28.180 回答
0

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

于 2011-06-19T19:57:11.263 回答