C ++ map erase(开始,结束)不起作用

时间:2013-08-01 22:17:24

标签: c++ map

我正在努力通过使用C ++ API来实现我的生活。通过map.erase(begin, end)方法,我希望删除[begin, end)之间的所有条目。所以我的方法实现了 TabletKey定义如下。

 79 void
 80 ObjectFinder::flush(uint64_t tableId) {
 81 
 82     RAMCLOUD_TEST_LOG("flushing object map");
 83     std::map<TabletKey, ProtoBuf::Tablets::Tablet>::iterator lower;
 84     std::map<TabletKey, ProtoBuf::Tablets::Tablet>::iterator upper;
 85     std::map<TabletKey, ProtoBuf::Tablets::Tablet>::iterator it;
 86     KeyHash keyHash = Key::getHash(tableId, "", 0);
 87     TabletKey key(tableId, keyHash);
 88 
 89     std::cout << "before the loop" << std::endl;
 90     for (it = tableMap.begin(); it != tableMap.end(); it++) {
 91         std::cout << it->first.first << std::endl;
 92     }
 93     lower = tableMap.lower_bound(key);
 94     upper = tableMap.upper_bound(key);
 95     
108     tableMap.erase(lower, upper);
109     std::cout << "After the erase" << std::endl;
110     for (it = tableMap.begin(); it != tableMap.end(); it++) {
111         std::cout << it->first.first << std::endl;
112     }
    }

但是,id值未被删除:

id = 99
before the loop
1
99
After the erase
1
99

我编写了自己的comparison函数,以重载默认方法:

 35 typedef std::pair<uint64_t, KeyHash> TabletKey;
 36 
 37 /*
 38  * The object CmpTabletKey is used to override the default comparison 
 39  * definition from the C++ Map.
 40  */
 41 struct CmpTabletKey {
 42     bool operator()(const TabletKey& key1, const TabletKey& key2) const {
 43         return ((key1.first < key2.first) ||
 44                 (key1.first == key2.first && key1.second < key2.second));
        }
    }

有人能给我一个线索,为什么erase没有按预期工作?我是否还必须将CmpTabletKey的定义提供给iterator? 的 更新 这是我的旧实现:它运行良好,并做我想要的: 但是,它是一种O(n)方法,我想要更快的实现:

117     std::map<TabletKey, ProtoBuf::Tablets::Tablet>::iterator it;
118     for (it = tableMap.begin(); it != tableMap.end(); ) {
119         if (tableId == it->first.first) {
120             tableMap.erase((it++)->first);
121         } else {
122             ++it;
123         }
124     }

4 个答案:

答案 0 :(得分:4)

从您的迭代器定义方式来看,您似乎没有使用自定义比较器创建地图。

我认为地图应该创建为:

std::map<TabletKey, ProtoBuf::Tablets::Tablet, CmpTabletKey > tableMap; //CmpTabletKey is passed as the comparator type

And your iterators become: 
std::map<TabletKey, ProtoBuf::Tablets::Tablet, CmpTabletKey>::iterator lower;
std::map<TabletKey, ProtoBuf::Tablets::Tablet, CmpTabletKey>::iterator upper;
std::map<TabletKey, ProtoBuf::Tablets::Tablet, CmpTabletKey>::iterator it;

如果您未指定CmpTabletKey作为类型,则地图将使用默认比较器。

答案 1 :(得分:3)

地图容器最多只保留每个键的一个副本,我想你想要做的是擦除TableID相同的所有元素,但是你已经使用一对来命令你的元素,所以你必须迭代所有映射并选择符合谓词的元素。

如果可以的话,你应该使用std :: multimap并创建一个仅包含TableID的比较器。

修改

那么你想要删除具有特定ID的所有元素。但实际上,您的地图正在寻找的是具有特定tableID和特定keyHash的元素。

您有多个解决方案,其中一个是O(n)(您拥有的解决方案),另一个选项是使用另一个满足您需求的数据结构。我认为你应该使用multimap或unordered_multimap(hast_table)。

答案 2 :(得分:1)

这是一个简化的例子,可以帮助您实现目标。

让我们用一对密钥制作地图:

#include <map>
#include <utility>

typedef std::pair<int, int> key_type;

std::map<key_type, void *> mymap = { { { 1, 2}, NULL }
                                   , { { 5, 0}, NULL }
                                   , { { 5, 7}, NULL }
                                   , { { 6, 3}, &mymap } };

现在假设我们要删除{em>第一个键部分等于mymap的{​​{1}}中的所有元素。这是一个解决方案:

5

答案 3 :(得分:0)

拿2 ...因为您的原始版本甚至不考虑key.second值,我猜这个问题出现在CmpTabletKey中,但这次出于不同的原因。与原始实现的功能等效的比较运算符是:

 35 typedef std::pair<uint64_t, KeyHash> TabletKey;
 36 
 37 /*
 38  * The object CmpTabletKey is used to override the default comparison 
 39  * definition from the C++ Map.
 40  */
 41 struct CmpTabletKey {
 42     bool operator()(const TabletKey& key1, const TabletKey& key2) const {
 43         return (key1.first < key2.first);
        }
    }

我怀疑,由于您当前的实现也考虑了.second值,因此功能从原始值更改。删除同一个异议的下限和上限之间的所有内容基本上会删除与该对象等效的所有键,但是您有KeyHash keyHash = Key::getHash(tableId, "", 0);TabletKey key(tableId, keyHash);,但key的键值不具体在你的地图中。您的比较运算符特定,因此它不会仅评估.first值的等效性。

同时,比较必须严格,因为我相信地图搜索基本上说“如果A!&lt; B和B!&lt; A,那么A = = B“。这意味着您将无法正确插入值,因为等效也不关心.second。我不认为您当前的实现会因为这些相互矛盾的定义而起作用。

编辑:Derp。试试这个:

 79 void
 80 ObjectFinder::flush(uint64_t tableId) {
 81 
 82     RAMCLOUD_TEST_LOG("flushing object map");
 83     std::map<TabletKey, ProtoBuf::Tablets::Tablet>::iterator lower;
 84     std::map<TabletKey, ProtoBuf::Tablets::Tablet>::iterator upper;
 85     std::map<TabletKey, ProtoBuf::Tablets::Tablet>::iterator it;
 86     //KeyHash keyHash = Key::getHash(tableId, "", 0);
        TabletKey keylower(tableId, KeyHash::MINIMUM);
        TabletKey keyupper(tableId, KeyHash::MAXIMUM);
 87     //TabletKey key(tableId, keyHash);
 88 
 89     std::cout << "before the loop" << std::endl;
 90     for (it = tableMap.begin(); it != tableMap.end(); it++) {
 91         std::cout << it->first.first << std::endl;
 92     }
 93     lower = tableMap.lower_bound(keylower);
 94     upper = tableMap.upper_bound(keyupper);
 95     
108     tableMap.erase(lower, upper);
109     std::cout << "After the erase" << std::endl;
110     for (it = tableMap.begin(); it != tableMap.end(); it++) {
111         std::cout << it->first.first << std::endl;
112     }
    }

其中KeyHash::MINIMUM是最低键哈希值的静态const,KeyHash::MAXIMUM是最大值。使用您当前的比较结构。