如何从映射中的集合中删除元素?

4

我在一个名为accesrightsByRankmap中遇到了从set中删除元素的问题。该映射的键是不同的ACCESRIGHTs: owner, modify, readnonemap的值是带有特定ACCESRIGHTs的访问者名称的sets。

    map<ACCESSRIGHT, set<string>>::const_iterator i;
    set<string>::const_iterator j;

    for(i = this->accessrightsByRank.begin(); i != this->accessrightsByRank.end(); i++){
        for(j = (*i).second.begin(); j != (*i).second.end(); j++){
            if( (*j).compare(p_Username) == 0){
                i->second.erase(j);
            }
        }
    }

我原以为 i->second 可以给我提供一个 set,从中可以删除没有特定 ACCESRIGHT 的用户名,但似乎我做错了什么。有人能解释一下为什么这不起作用,以及我应该如何调整我的代码吗?

这是我收到的错误:

IntelliSense: 无法匹配函数重载的实例 "std::set<_Kty, _Pr, _Alloc>::erase [with _Kty=std::string, _Pr=std::less<std::string>, _Alloc=std::allocator<std::string>]" 的参数列表和对象(对象具有阻止匹配的类型限定符) 参数类型为:(std::_Tree_const_iterator<std::_Tree_val<std::_Tree_simple_types<std::string>>>) 对象类型为:const std::set<std::string, std::less<std::string>, std::allocator<std::string>>


5
const_iterator 返回 const set<string>& 作为 second - Piotr Skotnicki
1
@PiotrSkotnicki 为什么不回答? - Glenn Teitelbaum
4
如果你需要进行线性搜索,那么你就打败了使用mapset的初衷。你应该使用set::find而不是线性搜索。 - PaulMcKenzie
3
请发布错误信息。很有可能它已经回答了你的问题。 - nwp
1
@nwp:原po应该学习const_iterator的教训,然后放弃这段代码并使用multimap。 - Beta
显示剩余5条评论
2个回答

3

根据Piotr Skotnicki他的评论中所示,您正在使用一个const_iterator。仅从名称就可以看出,这种迭代器不允许更改其指向的内容。请更改以下行:

map<ACCESSRIGHT, set<string>>::const_iterator i;
set<string>::const_iterator j;

转换为:

map<ACCESSRIGHT, set<string>>::iterator i;
set<string>::iterator j;

为了最快速的解决问题,可以使用上述方法。但是在此之后,请考虑下问题下面评论中给出的所有建议。


此外,进一步分析错误信息确实证明了这是根本原因,因为对象类型:const std::set<std::string, std::less<std::string> 声明没有可行的 erase 方法,从而确认了这种分析。 - WhozCraig
谢谢您提供的所有建议,我一定会记在心里!但是@BartoszKP,我认为您的意思是将map<ACCESSRIGHT,set<string>> ::const_iterator i;更改为map<ACCESSRIGHT,set<string>> ::iterator i;,因为set只允许使用const_iterators。 - Laura
@Laura。确实需要同时更改两个地方。请看我的更新。 - BartoszKP

3

总结所有评论,

  1. 您正在修改map和set。因此,应使用迭代器iterator而不是const_iterator。
  2. 要从set中删除某个值,您无需进行线性搜索。std::set::erase()有一个变体,可以接受要删除的值。
  3. i->second等同于且更易读取(*i).second。
  4. this->除非您有一个同名的局部变量,否则是多余的。

将它们结合起来,您将得到

map<ACCESSRIGHT, set<string>>::iterator i;

for(i = accessrightsByRank.begin(); i != accessrightsByRank.end(); i++){
    i->second.erase(p_Username);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接