增加迭代器,用作std :: multimap擦除范围的第一个和最后一个

时间:2016-01-19 22:03:23

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

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

This property can't be customized at runtime.

我使用命令#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 ++ 5.2.1)。

为什么迭代器的后递增会导致分段错误? 我宁愿说这应该创建这个迭代器的2个副本,将它们传递给擦除方法,“擦除任何东西”就像编码g++ --std=c++11 main.cpp然后递增myMap.erase(iter, iter);一样。

这个段错误背后有什么逻辑?

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

顺便说一句。 它在我使用预增量iter时进行编译,在这里它就像我上面提到的那样“什么都不删除”。

1 个答案:

答案 0 :(得分:4)

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

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

编译器可以自由地首先评估第二个参数。当您使用相同的迭代器但有副作用时,您将获得未定义的行为(参考C ++标准,第1.9 / 15节)。

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

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