我需要添加,存储和删除一些对象,例如Person
- Hobby
。任何人都可以有几个爱好,几个人可以有相同的爱好。所以,multimap是一个很好的容器,对吗?
在添加一对之前,我需要知道它是否尚未添加。我可以看到here没有标准的类方法可以知道,如果具体对,例如MM中存在Peter-Football
。因此,我编写了一个方法,如果该对存在,则返回一个正整数(等于mm.begin()和pair迭代器之间的距离),否则返回-1
。
然后我需要删除一对。我调用我的find
方法,返回一些正整数。我打电话给myMultiMap.erase(pairIndex);
,但由于某种原因,该对没有被删除。那是我的问题。显然,erase
方法需要iterator
,而不是int
。问题是:如何将整数转换为迭代器?
谢谢!
更新:
我试过这个c.begin() + int_value
,但在这一行上遇到了错误error: no match for ‘operator+’
....
答案 0 :(得分:3)
不是我赞成你的方法,但如果int
是begin()
和有问题的迭代器之间的距离,你可以使用
c.begin() + int_value
或
std::advance(c.begin(), int_value)
获取迭代器。对于非随机访问迭代器的迭代器,需要第二个版本。
为了您的个人理智(以及程序的速度),我建议您以某种形式直接返回迭代器。
有许多可能的接口可以解决这种或那种方式。我称之为“旧C方式”的是一个out参数:
bool find_stuff(stuff, container::iterator* out_iter) {
...
if(found && out_iter)
*out_iter = found_iter;
return found;
}
使用它:
container::iterator the_iter;
if(find_stuff(the_stuff, &the_iter)) ...
或
if(find_stuff(the_stuff, 0)) // if you don't need the iterator
这不是惯用的C ++,但Linus会很满意。
第二个可能且理论上合理的版本使用boost::optional
之类的东西来返回值。这样,您可以返回某个值或不返回任何值。
boost::optional<container::iterator> find_stuff(stuff) {
...
if(found && out_iter)
return found_iter;
return boost::none;
}
使用:
boost::optional<container::iterator> found = find_stuff(the_stuff);
if(found) {
do something with *found, which is the iterator.
}
或
if(find_stuff(the_stuff)) ...
第三种可能的解决方案是std::set::insert
方式,即。返回由标志和值组成的对:
std::pair<bool, container::iterator> find_stuff(stuff) {
...
return std::make_pair(found, found_iter);
}
使用:
std::pair<bool, container::iterator> found = find_stuff(the_stuff);
if(found.first) ...
答案 1 :(得分:2)
考虑将您的mulitmap<Person,Hoobby>
更改为set<pair<Person,Hobby> >
- 那么您现在就不会遇到任何问题。或者考虑更改为map<Person, set<Hobby> >
。这两个选项都不允许插入重复对。
答案 2 :(得分:1)
使用2套(不是多套)一套用于爱好,一套用于人,这两套用作过滤器,因此你不要两次添加同一个人(或hobbie)。这些集合上的插入操作给出了插入元素的迭代器(如果已经插入了元素,则为元素的“右”迭代器)。从插入到hobbies_set和person_set中获得的两个迭代器现在用作多图中的键和值
使用第三组(不是multi_set)作为关系而不是multi_map,可以提供在插入关系之前不需要检查的优点,如果它已经存在则不会再次添加,如果它不存在它将被添加。在两种方式中它都会返回一个迭代器和bool(告诉它是否已经存在或者是否已经添加)
数据结构:
typedef std::set<Hobbie> Hobbies;
typedef std::set<Person> Persons;
typedef std::pair<Hobbies::iterator,bool> HobbiesInsertRes;
typedef std::pair<Persons::iterator,bool> PersonsInsertRes;
struct Relation {
Hobbies::iterator hobbieIter;
Persons::iterator personIter;
// needed operator<(left for the as an exercies for the reader);
};
typedef set<Relation> Relations;
Hobbies hobbies;
Persons persons;
Relations relations;
插入:
HobbiesInsertRes hres = hobbies.insert(Hobbie("foo"));
PersonsInsertRes pres = persons.insert(Person("bar"));
relations.insert(Relation(hres.first, pres.first));
// adds the relation if does not exists, if it allready did exist, well you only paid the same amount of time that you would have if you would to do a check first.
查找
// for a concrete Person-Hobbie lookup use
relations.find(Relation(Hobbie("foo"),Person("Bar")));
// to find all Hobbies of Person X you will need to do some work.
// the easy way, iterate all elements of relations
std::vector<Hobbie> hobbiesOfX;
Persons::iterator personX = persons.find(Person("bar"));
std::for_each(relations.begin(), relations.end(), [&hobbiesOfBar, personX](Relation r){
if(r.personIter = personX)
hobbiesOfX.push_back(r.hobbieIter);
});
// other way to lookup all hobbies of person X
Persons::iterator personX = persons.find(Person("bar"));
relations.lower_bound(Relation(personX,Hobbies.begin());
relations.upper_bound(Relation(personX,Hobbies.end());
// this needs operator< on Relation to be implemented in a way that does ordering on Person first, Hobbie second.