C++:shared_ptr 作为 unordered_set 的键
考虑下面的代码
#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 文档并使用哈希函数,但没有运气。
有想法吗?
Consider the following code
#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
}
The question is: how come the size of s2 is 2 instead of 1? I'm pretty sure it must have something to do with the hash function. I tried looking at the boost docs and playing around with the hash function without luck.
Ideas?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
请注意,在 Boost <= 1.46.0 中,
boost::shared_ptr
的默认hash_value
是其布尔值、true
或假。
对于任何不为
NULL
的shared_ptr
,hash_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 >= 1.51.0 中的boost/function/hash/extensions.hpp
Notice that in Boost <= 1.46.0, the default
hash_value
of aboost::shared_ptr
is its boolean value,true
orfalse
.For any
shared_ptr
that is notNULL
,hash_value
evaluates to 1 (one), as the(bool)shared_ptr == true
.In other words, you downgrade a hash set to a linked list if you are using Boost <= 1.46.0.
This is fixed in Boost 1.47.0, see https://svn.boost.org/trac/boost/ticket/5216 .
If you are using
std::shared_ptr
, please define your own hash function, or useboost/functional/hash/extensions.hpp
from Boost >= 1.51.0正如您所发现的,插入到
s2
中的两个对象是不同的。As you found out, the two objects inserted into
s2
are distinct.make_shared
分配一个新的int
,并在其周围包装一个shared_ptr
。这意味着您的两个shared_ptr
指向不同的内存,并且由于您正在创建一个以指针值为键的哈希表,因此它们是不同的键。出于同样的原因,这将导致大小为 2:
在大多数情况下,您可以认为
shared_ptr
的作用就像指针一样,包括用于比较,但自动销毁除外。不过,您可以定义自己的哈希函数和比较谓词,并将它们作为模板参数传递给
unordered_map
: 但是,由于以下几个原因,这可能是一个坏主意:
x != y
但s4[x]
和s4[y]
是相同的。如果有人更改了哈希键指向的值您的哈希将会崩溃!即:
通常,对于哈希函数,您希望密钥不可变;无论以后发生什么,它总是比较相同的。如果您使用指针,通常希望指针标识是匹配的,如
extra_info_hash[&some_object] = ...
;无论some_object
的成员是什么,通常都会映射到相同的哈希值。由于键在插入后可变,因此实际执行此操作太容易了,从而导致哈希中出现未定义的行为。make_shared
allocates a newint
, and wraps ashared_ptr
around it. This means that your twoshared_ptr<int>
s point to different memory, and since you're creating a hash table keyed on pointer value, they are distinct keys.For the same reason, this will result in a size of 2:
For the most part you can consider
shared_ptr
s to act just like pointers, including for comparisons, except for the auto-destruction.You could define your own hash function and comparison predicate, and pass them as template parameters to
unordered_map
, though:However, this is probably a bad idea for a few reasons:
x != y
buts4[x]
ands4[y]
are the same.If someone ever changes the value pointed-to by a hash key your hash will break! That is:
Typically with hash functions you want the key to be immutable; it will always compare the same, no matter what happens later. If you're using pointers, you usually want the pointer identity to be what is matched on, as in
extra_info_hash[&some_object] = ...
; this will normally always map to the same hash value whateversome_object
's members may be. With the keys mutable after insertion is it all too easy to actually do so, resulting in undefined behavior in the hash.