可以将std::map
或std::unordered_map
的密钥与值的一部分共享吗?特别是如果密钥非常重要,比如说std::string
?
作为一个简单的例子,我们来一个Person对象:
struct Person {
// lots of other values
std::string name;
}
std::unordered_map<std::string, std::shared_ptr<Person>> people;
void insertPerson(std::shared_ptr<Person>& p) {
people[p.name] = p;
// ^^^^^^
// copy of name string
}
std::shared_ptr<Person> lookupPerson(const std::string& name) const {
return people[name];
}
我的第一个想法是指向该人的名称的包装,但我无法弄清楚如何按名称进行查找。
答案 0 :(得分:1)
出于您的目的,std::map
可以被视为包含std::set
的{{1}},根据该对的第一个元素对其进行排序(并因此可以高效访问)
如果键元素和值元素部分相同,则此视图特别有用,因为您不需要人为地分隔集合的值和键元素(并且您不需要围绕选择键的值编写包装器)。
相反,只需要提供一个自定义排序功能,该功能可以在集合上工作并提取相关的关键部分。
遵循这个想法,你的例子变成了
std::pair
作为替代方案,在这里您也可以删除自定义比较并按共享指针中的地址(支持auto set_order = [](auto const& p, auto const& s) { return p->name < s->name; };
std::set<std::shared_ptr<Person>, decltype(set_order)> people(set_order);
void insertPerson(std::shared_ptr<Person>& p) {
people.insert(p);
}
)对集合进行排序,因此可以直接在集合中使用:
<
在需要时将std::set<std::shared_ptr<Person> > people;
void insertPerson(std::shared_ptr<Person>& p) {
people.insert(p);
}
替换为set
(通常您还需要提供合适的哈希函数)。
编辑:可以使用unordered_set
执行查找:
std:lower_bound
编辑2 :但是,考虑到这个或多或少的丑陋的东西,你也可以按照你的主要思路,并使用一个小的包装器作为键的值,如
std::shared_ptr<Person> lookupPerson(std::string const& s)
{
auto comp = [](auto const& p, auto const& s) { return p->name < s; };
return *std::lower_bound(std::begin(people), std::end(people), s, comp);
}
使用它(未经测试)
struct PersonKey
{
PersonKey(std::shared_ptr<Person> const& p) : s(p->name) {}
PersonKey(std::string const& _s) : s(_s) {}
std::string s;
bool operator<(PersonKey const& rhs) const
{
return s < rhs.s;
}
};
通过
完成查找std::map<PersonKey, std::shared_ptr<Person> > m;
auto sptr = std::make_shared<Person>("Peter");
m[PersonKey(sptr)]=sptr;
现在我比我的第一个建议更喜欢这个; - )
答案 1 :(得分:0)
这是davidhigh回答的替代方案。
struct Person {
// lots of other values
std::string name;
}
struct StrPtrCmp {
bool operator()(const std::string* a, const std::string* b) const {
return *a < *b;
}
}
std::map<const std::string*, std::shared_ptr<Person>, StrPtrCmp> people();
void insertPerson(std::shared_ptr<Person>& p) {
people[&(p.name)] = p;
}
std::shared_ptr<Person> lookupPerson(const std::string& name) const {
return people[&name];
}
进行一些编辑以使其适用于std::unordered_map
:
struct StrPtrHash {
size_t operator()(const std::string* p) const {
return std::hash<std::string>()(*p);
}
};
struct StrPtrEquality {
bool operator()(const std::string* a, const std::string* b) const {
return std::equal_to<std::string>()(*a, *b);
}
};
std::unordered_map<const std::string*, std::shared_ptr<Person>, StrPtrHash, StrPtrEquality> people();