c++ - 用作 std::multimap 删除范围的第一个和最后一个的递增迭代器

标签 c++ c++11 stl iterator stdmap

在运行一个演示如何从 std::map/multimap 中删除范围的示例时,我注意到以下代码中的奇怪行为:

#include <map>
#include <iostream>
#include <string>

int main()
{
    std::multimap<int, std::string> myMap;

    myMap.insert(std::make_pair(3, "three1"));
    myMap.insert(std::make_pair(3, "three2"));
    myMap.insert(std::make_pair(3, "three3"));
    myMap.insert(std::make_pair(45, "fourty five"));
    myMap.insert(std::make_pair(-1, "minus one"));

    std::multimap<int, std::string>::iterator iter = myMap.find(3);
    if (iter != myMap.end()) {
        myMap.erase(iter, iter++); //segmentation fault(!)
    }

    for (auto element : myMap) {
        std::cout << element.first << " -> " << element.second << std::endl;
    }
    return 0;
}

我使用命令 g++ --std=c++11 main.cpp 构建(我使用 g++ 5.2.1)。

为什么迭代器的后增量会导致段错误? 我宁愿说,这应该创建该迭代器的 2 个拷贝,将它们传递到删除方法中,“不删除任何内容”,就像代码 myMap.erase(iter, iter); 一样,然后递增 iter

此段错误背后的逻辑是什么?

这是对 iter 迭代器的无效使用吗?如果是这样 - 为什么?

顺便说一句。 当我使用预增量 myMap.erase(iter,++iter) 时,它会进行编译,正如我上面提到的,它“不删除任何内容”。

最佳答案

未定义函数调用参数的求值顺序。所以当你写:

   myMap.erase(iter, iter++); //segmentation fault(!)

编译器可以自由地首先计算第二个参数,也可以不计算。当您使用相同的迭代器但有副作用时,您会得到未定义的行为(请参阅 C++ 标准,第 1.9/15 节)。

例如,如果编译器首先计算第二个参数 iter++,则递增的迭代器将用作第一个参数,而第二个参数不递增 iter。因此:传递给erase()的范围将是[std::next(iter), iter) - 该函数可能会尝试删除超出范围的元素(即UB)。

正如 David 在评论中所建议的,您可以使用 iter = myMap.erase(iter) (或使用没有副作用的范围)来解决问题。

关于c++ - 用作 std::multimap 删除范围的第一个和最后一个的递增迭代器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34887815/

相关文章:

c++ - 可能的 : Set Operations on Disparate Maps with Same Key Type?

c++ - STL 容器的元素生命周期

c++ - 将类型转换为唯一编号的模板元程序

c++ - 将基本类的对象扩展为复杂类的对象

c++ - 将指向成员函数的指针转换为 intptr_t

C++ Qt继承QMessageBox延迟用户输入以防止意外 Action

c++ - cmath std::pow 函数在分配给变量时给出错误的值?

c++枚举类整数不适用于数组下标

c++ - STL 自定义分配器

c++ - 程序员定义类的 STL 列表容器类