【问题标题】:Find a value in an unordered_set of shared_ptr在 shared_ptr 的 unordered_set 中查找一个值
【发布时间】:2015-09-16 15:50:18
【问题描述】:

我想在 unordered_set 中找到一个值,但是失败了:

typedef std::shared_ptr<int> IntPtr;

std::unordered_set<IntPtr> s;
s.insert(std::make_shared<int>(42));

bool found = s.find(std::make_shared<int>(42)) != s.end();
cout<<std::boolalpha<<found<<endl; // false

已尝试关注但仍然无法正常工作。

namespace std {
  template <> struct hash<IntPtr> {
    size_t operator()(const IntPtr& x) const noexcept {
      return std::hash<int>()(*x);
    }
  };
}

知道如何让它工作吗?

【问题讨论】:

  • 您需要了解两个共享指针“相等”的含义。
  • 你不应该专门化std::hash而不是你的类型...
  • shared_ptr的比较运算符比较指针值;不比较指向的实际对象。

标签: c++ shared-ptr unordered-set


【解决方案1】:

您存储了一个指向整数的指针。当您在集合中查找项目时,您不是在比较(指向的)整数,而是指针本身。

当你为搜索分配一个 new 指针到一个 new 整数对象时,它不会比较相等,因为它是一个不同的整数对象(即使它存储相同的值)。

您的选择是:

  1. 不要在你的集合中存储指向整数的指针,直接存储整数。

    那么,你的key是42,搜索42会找到,因为整数是按值比较的

  2. 存储指针并使用自定义散列和比较器来比较指向的整数而不是指针。

    您不应该(尝试)用您的哈希专业化污染std 命名空间,无论如何这还不够(哈希用于存储桶查找,但密钥仍与存储桶内的KeyEqual 进行比较)。只需为您的容器指定它们

#2 的示例代码:

#include <cassert>
#include <memory>
#include <unordered_set>

struct Deref {
    struct Hash {
        template <typename T>
        std::size_t operator() (std::shared_ptr<T> const &p) const {
            return std::hash<T>()(*p);
        }
    };
    struct Compare {
        template <typename T>
        size_t operator() (std::shared_ptr<T> const &a,
                           std::shared_ptr<T> const &b) const {
            return *a == *b;
        }
    };
};

int main() {
    std::unordered_set<std::shared_ptr<int>> sp;
    auto p = std::make_shared<int>(42);
    sp.insert(p);
    assert(sp.find(p) != sp.end()); // same pointer works
    assert(sp.find(std::make_shared<int>(42)) == sp.end()); // same value doesn't

    // with the correct hash & key comparison, both work
    std::unordered_set<std::shared_ptr<int>, Deref::Hash, Deref::Compare> spd;
    spd.insert(p);
    assert(spd.find(p) != spd.end());
    assert(spd.find(std::make_shared<int>(42)) != spd.end());
}

【讨论】:

    【解决方案2】:

    根据here

    请注意,shared_ptr 的比较运算符只是比较指针值;不比较指向的实际对象。

    所以found 只有当shared_ptr 指向同一个对象时才会为真:

    typedef std::shared_ptr<int> IntPtr;
    
    std::unordered_set<IntPtr> s;
    IntPtr p = std::make_shared<int>(42);
    s.insert(p);
    
    bool found = s.find(p) != s.end();
    cout<<std::boolalpha<<found<<endl; // true
    

    【讨论】:

      猜你喜欢
      • 2018-11-18
      • 2021-09-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多