Reputation: 1176
While running an example that shows how to erase a range from std::map/multimap I have noticed strange behaviour in the following code:
#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;
}
Which I build with command g++ --std=c++11 main.cpp
(I use g++ 5.2.1).
Why post-incrementation of my iterator causes a Segmentation fault?
I would rather say that this should create 2 copies of this iterator, pass them into the erase method, "erase nothing" just as would code myMap.erase(iter, iter);
and then increment the iter
.
What logic stands behind this segfault?
Is this an invalid use of iter
iterator? If so - why?
BTW.
It compiles when I use pre-incrementation myMap.erase(iter, ++iter)
and here it "erase nothing" as I mentioned above.
Upvotes: 2
Views: 163
Reputation: 73366
The order of evaluation of the arguments to a function call is not defined. So when you write:
myMap.erase(iter, iter++); //segmentation fault(!)
the compiler is free to evaluate the second argument first, or not. As you use the same iterator, but have a side effect, you get Undefined Behaviour (refer to C++ standard, section 1.9/15).
For example, if the compiler evaluates first the second argument iter++
, the incremented iterator would be used as the first argument, while second argument is not incremented iter
. As a consequence: the range passed to erase() would be [std::next(iter), iter)
- the function might attempt to erase elements that are out of range (i.e. UB).
As suggested by David in the comments, you can solve the issue with iter = myMap.erase(iter)
(or using a range without side effects).
Upvotes: 4