将[]索引到无序映射时出现段错误

时间:2017-02-07 06:02:20

标签: c++

所以我的无序地图是从字符串到双重

的映射
unordered_map<string,double> u_map;
unordered_map<string,double> other_u_map;

我这样迭代

for (auto it : u_map){
   if(isTrue){
       other_u_map[it.first] = returnsDouble(); //Segfaults here
       u_map.erase(it.first);
   }
}

对于一些测试用例,它运行完美而没有segfaulting。然后其他时候它会在这一行之后发生段错误,这没有任何意义,因为我所做的就是为它指定一个双键。如果密钥不存在,那么它应该创建一个。由于我使用的是C ++数据类型(字符串和双精度型),所以创建我自己的数据结构不会导致段错误或访问mem越界,就像我在其他SO问题中看到的那样。这可能是使用

的问题
for (auto it : u_map)

或者这可能是在这一行之前发生的问题

等我忘了添加我擦除u_map中的键是问题吗?

2 个答案:

答案 0 :(得分:5)

不幸的是,你不能在这里使用基于范围的for循环,你必须明确地使用迭代器。

for (auto it = std::begin(u_map); it != std::end(u_map); ) {
    //                                                  ^ no it++ here
    if (isTrue) {
        other_u_map[it->first] = returnsDouble();
        //             ^ changed to -> because it is now iterator
        it = u_map.erase(it);
    } else {
        ++it;
    }
}

为什么原始代码错了?

C ++代码中最常见的一个错误是使用无效的迭代器。当您的集合更新时,迭代器不会更新。请记住,问题中基于for循环的范围等同于:

for (auto pos = std::start(u_map), end = std::start(u_map);
     pos != end; ++pos) {
    auto it = *pos;
    ...
}

问题是.erase()使pos无效,因此之后调用++pos是违法的。

答案 1 :(得分:1)

  

等我忘了添加我擦除u_map中的键是问题吗?

是。 Range-based for loop做同样的事情:

{
    auto && __range = range_expression ; 
    auto __begin = begin_expr ;
    auto __end = end_expr ;
    for ( ; __begin != __end; ++__begin) { 
        range_declaration = *__begin; 
        loop_statement 
    } 
} 

这意味着元素在循环内被擦除的事实将导致访问不存在的元素(即,超出当前范围unordered_map);这是UB。