【问题标题】:How to compute hash of std::weak_ptr?如何计算 std::weak_ptr 的哈希值?
【发布时间】:2022-01-04 22:21:30
【问题描述】:

所以我有使用std::weak_ptr 并将它们维护在std::set 中的代码,并且工作得很好——并且已经工作了5 或7 年。最近我想我会在std::unordered_set(嗯,实际上是在f14::F14ValueSet)中使用它们,为此,我需要一个哈希值。目前还没有std::hash<std::weak_ptr>,那我该怎么办呢?

答案似乎是“只是散列控制块”,正如这个问题和回复所暗示的那样:Why was std::hash not defined for std::weak_ptr in C++0x?,但是我如何访问控制块?在 glibc 中,它位于 __weak_ptr<>::_M_refcount._M_pi-> 但这是私有的(并且是特定于实现的)。我还能做什么?

一个答案是“等一下”:maybe someday there will be a standard owner_hash() for std::weak_ptr,但我更喜欢现在可用的东西。

【问题讨论】:

  • 看起来如果你不想等待,你需要实现你自己的弱指针类型,暴露适当的数据来做一个稳定的哈希。
  • 嗯,stackoverflow.com/questions/13695640/… 中给出的答案显然是错误的,因为它与 C++ 标准委员会对此事的看法相冲突。它似乎只是“你做不到”是正确的,但解释原因是错误的。应该撤回或修改该答案。

标签: c++ hash weak-ptr


【解决方案1】:

制作你自己的增强弱指针。

它存储一个哈希值,并基于owner_before()支持==

必须shared_ptrs 制作这些,因为没有强引用的弱ptr 不能被散列以匹配其所有者;这可能会创建两个比较相等但散列不同的增强弱 ptr。

template<class T>
struct my_weak_ptr {
  // weak ptr API clone goes here.  lock() etc.

  // different ctor:
  my_weak_ptr(std::shared_ptr<T>const& sp){
    if(!sp) return;
    ptr=sp;
    hash = std::hash<T*>{}(sp.get());
  }
  std::size_t getHash()const{return hash;}
  friend bool operator<(my_weak_ptr const& lhs, my_weak_ptr const& rhs){
    return lhs.owner_before(rhs);
  }
  friend bool operator!=(my_weak_ptr const& lhs, my_weak_ptr const& rhs){
    return lhs<rhs || rhs<lhs;
  }
  friend bool operator==(my_weak_ptr const& lhs, my_weak_ptr const& rhs){
    return !(lhs!=rhs);
  }
private:
  std::weak_ptr<T> ptr;
  std::size_t hash=0;
};

这些具有稳定、合理的哈希值。虽然回收的对象指针会导致哈希冲突,但只要它们不共享控制块,它们就不会相等。

namespace std{template<class T>struct hash<some_ns::my_weak_ptr<T>>{
  std::size_t operator()(my_weak_ptr<T> const& wp)const{return wp.getHash();}
};}

一个警告:使用别名构造函数可能会导致病态结果。因为相等是基于控制块相等,而不是指针值。

【讨论】:

  • 存储指针值而不是哈希作为成员将允许通过指针值实现相等。虽然这与通常的 weak_ptr 行为不一致,但这对于构造函数的别名情况可能更好
  • @alex 比较和散列悬空指针对我来说听起来像 UB;在 C++ 中,对删除指针的操作限制相当极端。
  • 哦,然后在它仍然有效的时候转换为uintptr_t。尽管这可能会导致其他(可能只是理论上的)问题。可能你是对的,应该立即散列。
  • 我想编辑答案以包含一些小问题:说 struct hashable_weak_ptr : public std::weak_ptr&lt;T&gt; 避免了复制所需的 API。还提供template&lt;class T&gt; struct owner_less&lt;mynamespace::hashable_weak_ptr&lt;T&gt;&gt; 允许它在std::set 中使用,而需要template&lt;class T&gt; struct hash&lt;mynamespace::hashable_weak_ptr&lt;T&gt;&gt; 来完成示例。如果可以,我可以进行这些编辑吗?
  • @linas 公共继承允许切片。所以,我不会。 API 没有那么大。可以进行私有继承和使用。我的版本还有&lt;;套装不需要额外的东西吗?
猜你喜欢
  • 2014-04-01
  • 2016-06-23
  • 2011-12-19
  • 2014-09-16
  • 2018-04-17
  • 1970-01-01
  • 2015-09-14
  • 2023-03-07
  • 2019-05-31
相关资源
最近更新 更多