C ++映射上的迭代给出了无限循环 [英] iteration over a C++ map giving infinite loop

查看:67
本文介绍了C ++映射上的迭代给出了无限循环的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 C ++ 中具有以下方法,该方法仅从地图中删除与特定 tableId 相关的元素.

I have the following method in C++ that only removes the elements associated with a particular tableId from a map.

 69 void
 70 ObjectFinder::flush(uint64_t tableId) {
 71 
 72     RAMCLOUD_TEST_LOG("flushing object map");
 74     // find everything between tableId, 0
 75     // keep scanning util find all the entries for that table
 76     std::map<TabletKey, ProtoBuf::Tablets::Tablet>::const_iterator it;
 79     for (it = tableMap.begin(); it != tableMap.end(); it++) {
 80         TabletKey current = it->first;
 81         if (tableId == current.first) {
 82             tableMap.erase(current);
 83         }
 84     }
 85     std::cout << "hello" << std::endl;
 87 }

使用 gdb 进入代码,我发现在 for 循环的迭代之后发生了无限循环.永远不会打印出 85 行.我假设正在发生悬空指针.在第一个循环中,删除了 current 元素,然后在接下来的两个循环中什么也没有发生,然后出现了无限循环.我完全不知道为什么会这样.有人有想法或曾经经历过吗?

Stepping into the code with gdb I found out that an infinite loop is happening after the iteration of the for loop. The line 85 is never printed out. I'm assuming a dangling pointer is happening. In the first loop, the current element is removed, then in the next two nothing happens, and then I have the infinite loop. I'm total clueless why is this happening. Does someone has an idea or has experienced it before?

我的代码的另一个更聪明的版本是使用 lower_bound upper_bound 查找 id 的开始位置(这样可以节省一些计算时间):

Another smarter version of my code is to use lower_bound and upper_bound to find where the id begins (it would save some computing time):

 69 void
 70 ObjectFinder::flush(uint64_t tableId) {
 71 
 72     RAMCLOUD_TEST_LOG("flushing object map");
        KeyHash keyHash = Key::getHash(tableId, "", 0);
 74     // find everything between tableId, 0
 75     // keep scanning util find all the entries for that table
 76     std::map<TabletKey, ProtoBuf::Tablets::Tablet>::const_iterator lower;
        std::map<TabletKey, ProtoBuf::Tablets::Tablet>::const_iterator upper;
        TabletKey key(tableId, keyHash);

        lower = tableMap.lower_bound(key);
        upper = tableMap.upper_bound(key);
        tableMap.erase(lower, upper);
 85     std::cout << "hello" << std::endl;
 87 }

我得到:

/home/ribeiro.phillipe/ramcloud/src/ObjectFinder.cc:81: error: no matching function for call to ‘std::map<std::pair<long unsigned int, long unsigned int>, RAMCloud::ProtoBuf::Tablets_Tablet, std::less<std::pair<long unsigned int, long unsigned int> >, std::allocator<std::pair<const std::pair<long unsigned int, long unsigned int>, RAMCloud::ProtoBuf::Tablets_Tablet> > >::erase(std::_Rb_tree_const_iterator<std::pair<const std::pair<long unsigned int, long unsigned int>, RAMCloud::ProtoBuf::Tablets_Tablet> >)’
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../../../include/c++/4.4.6/bits/stl_map.h:566: note: candidates are: void std::map<_Key, _Tp, _Compare, _Alloc>::erase(typename std::_Rb_tree<_Key, std::pair<const _Key, _Tp>, std::_Select1st<std::pair<const _Key, _Tp> >, _Compare, typename _Alloc::rebind<std::pair<const _Key, _Tp> >::other>::iterator) [with _Key = std::pair<long unsigned int, long unsigned int>, _Tp = RAMCloud::ProtoBuf::Tablets_Tablet, _Compare = std::less<std::pair<long unsigned int, long unsigned int> >, _Alloc = std::allocator<std::pair<const std::pair<long unsigned int, long unsigned int>, RAMCloud::ProtoBuf::Tablets_Tablet> >]
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../../../include/c++/4.4.6/bits/stl_map.h:581: note:                 typename std::_Rb_tree<_Key, std::pair<const _Key, _Tp>, std::_Select1st<std::pair<const _Key, _Tp> >, _Compare, typename _Alloc::rebind<std::pair<const _Key, _Tp> >::other>::size_type std::map<_Key, _Tp, _Compare, _Alloc>::erase(const _Key&) [with _Key = std::pair<long unsigned int, long unsigned int>, _Tp = RAMCloud::ProtoBuf::Tablets_Tablet, _Compare = std::less<std::pair<long unsigned int, long unsigned int> >, _Alloc = std::allocator<std::pair<const std::pair<long unsigned int, long unsigned int>, RAMCloud::ProtoBuf::Tablets_Tablet> >]
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../../../include/c++/4.4.6/bits/stl_map.h:596: note:                 void std::map<_Key, _Tp, _Compare, _Alloc>::erase(typename std::_Rb_tree<_Key, std::pair<const _Key, _Tp>, std::_Select1st<std::pair<const _Key, _Tp> >, _Compare, typename _Alloc::rebind<std::pair<const _Key, _Tp> >::other>::iterator, typename std::_Rb_tree<_Key, std::pair<const _Key, _Tp>, std::_Select1st<std::pair<const _Key, _Tp> >, _Compare, typename _Alloc::rebind<std::pair<const _Key, _Tp> >::other>::iterator) [with _Key = std::pair<long unsigned int, long unsigned int>, _Tp = RAMCloud::ProtoBuf::Tablets_Tablet, _Compare = std::less<std::pair<long unsigned int, long unsigned int> >, _Alloc = std::allocator<std::pair<const std::pair<long unsigned int, long unsigned int>, RAMCloud::ProtoBuf::Tablets_Tablet> >]
make: *** [obj.master/ObjectFinder.o] Error 1

是因为我没有支持该功能的 C ++ 版本?

is that because I don't have a C++ version that support that?

推荐答案

您的代码具有未定义的行为,因为您使用的是刚刚失效的迭代器.这样做:

Your code has undefined behaviour because you're using an iterator that you've just invalidated. Do it like this:

for (it = tableMap.begin(); it != tableMap.end(); )
{
    if (tableId == it->first.first) { tableMap.erase(it++); }
    else                            { ++it; }
}

这篇关于C ++映射上的迭代给出了无限循环的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆