在 shared_ptr 的 unordered_set 中查找值

Find a value in an unordered_set of shared_ptr

我想在 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);
    }
  };
}

知道如何让它发挥作用吗?

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

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

您的选择是:

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

    那么,你的键是42,搜索42就会找到它,因为整数是按值

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

    你不应该(尝试)用你的散列特化来污染 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());
}

根据here

Note that the comparison operators for shared_ptr simply compare pointer values; the actual objects pointed to are not compared.

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

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