2015-09-16 4 views
2

Я хотел бы найти значение в unordered_set, но не удалось:Найти значение в качестве unordered_set из shared_ptr

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); 
    } 
    }; 
} 

Любая идея, как это сделать?

+0

Вы должны понимать, что это значит для двух указателей общими, чтобы быть «равным». –

+1

Вы не должны специализироваться на 'std :: hash' не для ** вашего ** типа ... – Jarod42

+0

Операторы сравнения для' shared_ptr' сравнивать значения указателя; фактические объекты, на которые указывает, не сравниваются. – dasblinkenlight

ответ

4

Вы сохранили указатель на целое число. Когда вы просматриваете элементы в наборе, вы не сравниваете целое число (заостренное), а указатель.

При выделении указателя нового к новому целого объекта для поиска, он не будет сравнивать равен, потому что это другое число объектов (даже если он сохраняет то же значение).

варианты:

  1. Не следует хранить указатели на целые числа в вашем наборе, просто хранить целые числа непосредственно.

    Затем ваш ключ 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()); 
} 
1

Согласно 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 

 Смежные вопросы

  • Нет связанных вопросов^_^