我有一个这样的集合:set<weak_ptr<Node>, owner_less<weak_ptr<Node> > > setName;
它工作得很好。但是我想把它改成一个无序的集合。然而,当我这样做的时候,我得到了大约六页的错误。你知道怎么做吗?
在浏览了所有页面的错误消息后,我找到了可能有帮助的代码行。
/usr/include/c++/4.7/bits/functional_hash.h:60:7: error: static assertion failed: std::hash is not specialized for this type
/usr/include/c++/4.7/bits/stl_function.h: In instantiation of ‘bool std::equal_to<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = std::weak_ptr<Node>]’:
发布于 2012-12-04 15:30:16
请阅读下面的 答案,因为我的答案是不正确的,尽管我是公认的解决方案。
由于unordered_sets
是基于散列的,因此必须为std::weak_ptr数据类型提供散列function object。
如果您查看unordered_set模板参数
template<class Key,
class Hash = std::hash<Key>,
class Pred = std::equal_to<Key>,
class Alloc = std::allocator<Key> >
class unordered_set;
您会注意到,std::unordered_set为您提供了一个默认的std::hash<>模板参数。但是,由于std::hash只为数据类型的specific set提供专门化,您可能需要提供自己的专门化。
template<typename T>
struct MyWeakPtrHash : public std::unary_function<std::weak_ptr<T>, size_t> {
size_t operator()(const std::weak_ptr<T>& wp)
{
// Example hash. Beware: As zneak remarked in the comments* to this post,
// it is very possible that this may lead to undefined behaviour
// since the hash of a key is assumed to be constant, but will change
// when the weak_ptr expires
auto sp = wp.lock();
return std::hash<decltype(sp)>()(sp);
}
};
编辑:您还需要提供一个相等函数,因为没有提供weak_ptr的std::equal_to。在"Equality-compare std::weak_ptr" on Stackoverflow中采用一种可能的方法来完成此操作
template<typename T>
struct MyWeakPtrEqual : public std::unary_function<std::weak_ptr<T>, bool> {
bool operator()(const std::weak_ptr<T>& left, const std::weak_ptr<T>& right)
{
return !left.owner_before(right) && !right.owner_before(left);
}
};
所有这些结合在一起,给我们提供了以下内容:
std::unordered_set<std::weak_ptr<T>,
MyWeakPtrHash<T>,
MyWeakPtrEqual<T>> wpSet;
发布于 2015-06-18 17:49:25
简短而不幸的答案是,虽然shared_ptr<>
可以安全地用作无序集合或映射中的键,但weak_ptr<>
不能也不能。再多的花招也不能保证它的安全。
这是因为weak_ptr
的接口不公开对共享控制对象的访问,这是在有序集或映射中使用时按owner_before()
进行比较的基础。
虽然锁定指针然后散列shared_ptr
似乎是合理的,但事实并非如此。如果最后一个shared_ptr
超出作用域,则哈希值将更改,这将导致下次迭代您的集或映射时出现未定义的行为。这很可能不会被注意到,直到你的代码在客户面前生产,你偶尔会遇到意想不到的和莫名其妙的功能损失,但你的单元测试仍然会毫无瑕疵地通过,给你一个错误的想法,你的测试覆盖率很好,你的代码是可靠的,应该归咎于用户、硬件或网络。
因此,总而言之,如果您打算使用weak_pt
r来构建您的无主对象缓存(它们非常适合),那么您需要使用std::set<weak_ptr>
并遭受极小的性能影响(尽管在现实中,这与保护set的mutex
所造成的性能损失相比会相形见绌)。
如果你真的想使用一个weak_ptr
作为一个无序键,你必须自己编写(提示:使用共享控制块的地址作为散列函数的基础)。
发布于 2014-03-01 05:48:07
我不认为建议的散列函数是正确的。如果指向该对象的所有共享指针都消失了,则weak_ptr<X>::lock()
将返回空的shared_ptr,其散列值可能为零。因此哈希函数可以在一段时间内返回不同的值。
我认为正确的解决方案是使用boost::unordered_map<X*, boost::weak_ptr<X>>
。类型X*
可以很容易地用作散列映射的关键字,而weak_ptr<X>
作为值让您有机会了解被引用的对象是否仍然存在。
要将值存储到此哈希中,您可以使用以下内容:
if (boost::shared_ptr<X> p = wp.lock()) {
// weak_ptr is still valid
ptrs.insert(std::make_pair(p.get(), p));
}
https://stackoverflow.com/questions/13695640
复制相似问题