我有一个Person类,它有一个name属性(std :: string).
我想创建一个查找表,一个std :: unordered_map,所以我可以通过他们的名字找到一个Person.但是,鉴于一个人,我也希望能够得到他们的名字.
这需要存储两次名称 – 一次作为地图的键,一次存在于人物对象内,如下面的代码所示.
由于我有很多人一次加载到内存中,我不希望两次存储他们的名字的开销.
我尝试在Person类中使用对键的引用/指针,但这会产生问题,因为映射似乎在修改时重新调整其数据,并且引用变为无效.
我也尝试过使用std :: unordered_set,但这意味着每次我想执行查找时都需要构造一个完整的Person对象.
是否有任何方法可以使无序映射的键和值共享相同的数据?
#include <iostream> #include <unordered_map> class Person { private: const std::string _name; public: Person( const std::string& name ) : _name( name ) { } const std::string& get_name() const { return _name; } }; int main() { auto my_set = std::unordered_map<std::string,std::shared_ptr<Person>>(); my_set.insert( { "alice",std::shared_ptr<Person>( new Person( "alice" )) } ); my_set.insert( { "bob",std::shared_ptr<Person>( new Person( "bob" )) } ); my_set.insert( { "charlie",std::shared_ptr<Person>( new Person( "charlie" )) } ); std::cout << my_set.find( "bob" )->second->get_name() << std::endl; return 0; }
解决方法
使用std :: set,您可以使用透明比较器(std :: unordered_set似乎不支持:/):
struct LessPerson { using is_transparent = void; // enable "transparent" comparer template <typename T1,typename T2> bool operator ()(const T1& t1,const T2& t2) const { // Compare only "name". return toString(t1) < toString(t2); } // trivial one const std::string& toString(const std::string& s) const { return s; } // the one why we create the class const std::string& toString(const Person& p) const { return p.get_name(); } // A tricky one to handle dereference of (smart) pointers. template <typename T,std::enable_if_t<std::is_same<Person,std::decay_t<decltype(*std::declval<T>())>>::value>* = nullptr> const std::string& toString(const T& p) const { return (*p).get_name(); } };
然后使用它:
auto my_set = std::set<std::shared_ptr<Person>,LessPerson>(); my_set.insert( { std::make_shared<Person>("alice") } ); my_set.insert( { std::make_shared<Person>("bob") } ); my_set.insert( { std::make_shared<Person>("charlie") } ); auto it = my_set.find("bob"); // search using "bob" directly without creating a new Person