C++ 避免重复存储地图密钥
假设我有一个C++ 避免重复存储地图密钥,c++,reference,stdmap,C++,Reference,Stdmap,假设我有一个std::map(或unordered_map),我想从迭代器/引用/指向内容的指针访问密钥 有没有一种方法可以在没有两个std::string键副本的情况下实现这一点(一个属于map,一个位于content对象内部)?一个可以引用另一个吗?两者都可以引用相同的值。例如: #include <stdio.h> #include <string> #include <map> struct xx { std::string mykey; int v
std::map
(或unordered_map
),我想从迭代器/引用/指向内容的指针访问密钥
有没有一种方法可以在没有两个
std::string
键副本的情况下实现这一点(一个属于map,一个位于content对象内部)?一个可以引用另一个吗?两者都可以引用相同的值。例如:
#include <stdio.h>
#include <string>
#include <map>
struct xx { std::string mykey; int value; };
int main (int argc, char **argv)
{
std::string key1("the-key");
std::map<std::string, xx> map;
map[key1].mykey = key1;
map[key1].value = 13;
std::string &lookup_key = map[key1].mykey;
printf("%d\n", map[lookup_key].value);
}
#包括
#包括
#包括
结构xx{std::string mykey;int value;};
int main(int argc,字符**argv)
{
std::字符串键1(“键”);
地图;
map[key1].mykey=key1;
映射[key1]。值=13;
std::string&lookup_key=map[key1].mykey;
printf(“%d\n”,映射[lookup\u key].value);
}
为什么不创建两个对象:
std::set<std::string> wordSet;
std::map<std::string*, T> yourMap;
std::set单词集;
映射你的地图;
T必须包含指向std::string的指针,并且您的映射需要自定义比较器。另外,您可以在某些类中包装所有这些。
您会考虑使用Booo::BIMAP吗?下面是一个简单的例子:
#include <boost/bimap.hpp>
#include <string>
struct Person
{
Person()
{}
Person(const std::string& f, const std::string& l, int a) : first(f), last(l), age(a)
{}
std::string first;
std::string last;
int age;
};
bool operator <(const Person& lhs, const Person& rhs)
{
if(lhs.last < rhs.last)
return true;
return false;
}
std::ostream& operator << (std::ostream& os, const Person& p)
{
os << "First Name: " << p.first << " Last Name: " << p.last << " Age: " << p.age;
return os;
}
int main()
{
typedef boost::bimap<std::string, Person> people;
typedef people::value_type value;
people m;
m.insert(value("12345",Person("fred", "rabbit", 10)));
m.insert(value("67890",Person("benjamin", "bunny", 12)));
Person p = m.left.at("12345");
std::cout << "Person with serial no. 12345 is: " << p << "\n";
std::cout << "Serial number of " << p << " is: " << m.right.at(p) << "\n";
}
#包括
#包括
结构人
{
人()
{}
Person(const std::string&f,const std::string&l,int a):第一(f),最后(l),年龄(a)
{}
std::首先是字符串;
std::最后一个字符串;
智力年龄;
};
bool操作员他们之所以这么做是因为这很危险。您必须保证被设置为off的std::string
成员不会更改值,否则整个映射将失效。有趣的是,第一个出现在我脑海中的解决方案看起来非常的粗糙,看起来像UB,但我相信我会非常小心地避开UB
struct key_type {
mutable const char* ptr;
};
bool operator<(const key_type& lhs, const key_type& rhs)
{return strcmp(lhs.ptr, rhs.ptr)<0;}
struct person {
std::string name;
int age;
};
person& people_map_get(std::map<key_type, person>& map, const char* name) {
auto it = map.insert(name, person{name}).first; //grab, possibly insert
if->first.ptr = it->second.name.c_str(); //in case of insert, fix ptr
return it->second;
}
person& people_map_assign(std::map<key_type, person>& map, person p) {
auto pair = map.insert(name, p); //grab, possibly insert
auto it = pair.first;
if (pair.second == false)
it->second = std::move(p);
if->first.ptr = it->second.name.c_str(); //ptr probably invalidated, so update it
return it->second;
}
int main() {
std::map<key_type, person> people;
people_map_assign(people, person{"ted"});
person frank = people_map_get(people, "frank");
}
struct key\u类型{
可变常量字符*ptr;
};
bool运算符second.name.c_str()//如果是插入,请固定ptr
返回->秒;
}
人员和人员地图分配(标准::地图和地图,人员p){
auto pair=map.insert(name,p);//抓取,可能是插入
auto it=pair.first;
if(pair.second==false)
it->second=std::move(p);
如果->first.ptr=it->second.name.c_str();//ptr可能无效,请更新它
返回->秒;
}
int main(){
地图人;
人员分配(人员,人员{“ted”});
person-frank=people\u-map\u-get(people,“frank”);
}
正如我所希望的,这是疯狂接近UB,非常不推荐。基本上,在插入/查找过程中,键指向临时对象或输入字符串,然后一旦插入/查找对象,键就会更改为指向字符串成员中包含的值,并且只要您从未执行任何会使.c_str()的返回值无效的操作
在任何包含的人
对象上,一切都几乎不起作用。我想。使用std::set
如何,其中C
比较T
中存储的字符串?@Daniel:但是我需要提供一个完整的T
对象进行查找,而不仅仅是std::string
,对吗?或者可以重载C
将T
与T
进行比较,也可以将T
与std::string
进行比较?啊,我看到C++14将添加一个模板化的find
成员,以搜索任何可以与T
进行比较的类型。可能用于此类目的的虚拟T
可以工作(您刚刚设置字符串的地方)。但我可以看到它可能会变为akward,这取决于T
是什么。@BenVoigt:迭代器和指向内容的引用/指针之间有区别。关联容器的迭代器指的是std::pair
(即,Container::value\u type
,因此在这种情况下不需要做任何事情。我想你误解了这个问题。如果我有auto&content=map[key1];
,我需要能够再次从内容
到键1
。一种方法是将键的副本放在内容类型中。我问是否有办法避免副本。哦,这就澄清了。唯一的方法是遍历整个集合,找到具有相同地址的内容。或者保留第二个collec它通过地址或T的其他内容给出地图。顺便说一句,正是这一点让我像以前一样回答:“一个可以作为另一个的参考吗?”这可能行得通,但我觉得它是为这样一种情况设计的:你只有一个mapped_type
元素的副本,可能是合成的,没有直接指针之类的元数据。正如dribeas指出的,我可以保留一个std::pair*
,并且可以访问这两个元素。否则,正如dribeas解释的,密钥有一个固定的内存位置,因此,内容可以存储指向该键的指针。我认为这不会那么疯狂。我不认为您可以将其存储在t
中,因为t
在声明时是不完整的,并且pair
要求它是完整的。不,等等,因为指向pair
的指针可能不需要它……我不确定我是否需要它我绝对可以在T
中保留一个const std::string*
。我明白你关于将value\u type*
或迭代器放在另一个元素中的观点,但我不需要在那里完成std::pair
,因为我只存储了一个指针。太好了!这比我的答案好,其他的事实上,T
在映射之后才是“完整”的。对,std::pair
似乎没有任何构造函数为第二个子对象构造函数提供对第一个子对象的引用,因此在构造之后必须存储指针。