0

When I tried to delete end() element from the map using erase I got no issues in compilation but on later printing the map.begin() key/mapped_value I got segmentation fault:

 //RELEVANT HEADERS

 //main function starts

 map<int, string> m;
 m[0] = "hello";
 m[1] = "Mello";

 m.erase(m.end());

 cout<<(m.begin())->second;

OUTPUT: Segmentation fault

My question is: on trying to delete the end() element nothing would've happened to the structure of map m as end refers to one past the real end element, so what really triggered that segmentation fault as the memory structure still holds same as before deletion.

Agrudge Amicus
  • 1,033
  • 7
  • 19

2 Answers2

2

As you can see in e.g. cppreference's documentation on std::map::erase, the iterator passed to it must be a valid iterator into the container that erase is called on and it has to be dereferencable.

The end() iterator is not dereferencable. Therefore passing it to erase violates erase's precondition, which means that your program has undefined behavior.

Undefined behavior means that there is no guarantee on what the program will do (or whether it will compile at all) and therefore it is entirely possible that it seems to work until somewhere later in your program and/or that you get a segmentation fault. These are possible manifestations of undefined behavior.


Practically speaking, the erase call probably dereferences some pointer contained in the iterator that doesn't point to any element and that triggers the segmentation fault. But that is an implementation detail dependent on your standard library implementation and it doesn't really matter anyway, as the rules are given by the language and described above.

walnut
  • 21,629
  • 4
  • 23
  • 59
2

std::map::erase() can take one of three types of parameters:

  • iterator
  • iterator range
  • key value

You're passing an iterator but it is end(), which is one past the last element in the map. According to cppreference for std::map:erase():

The iterator pos must be valid and dereferenceable. Thus the end() iterator (which is valid, but is not dereferenceable) cannot be used as a value for pos.

So for std::map::erase() to work with an iterator the element pointed to must be a valid element within the map. Otherwise all bets are off and you can get undefined behaviour.

jignatius
  • 6,304
  • 2
  • 15
  • 30
  • I have mentioned the same but the question is different. – Agrudge Amicus Feb 16 '20 at 06:04
  • @AgrudgeAmicus You are trying to perform an operation that just isn't valid. That's the issue. `end()` points to the memory location that is one past the last element. Using `end()` with `erase()` violates the requirements of the parameters. Hence the seg fault in your case. `end()` is typically used for checking you are within the bounds of the map - like in a for loop or with algorithm functions. – jignatius Feb 16 '20 at 07:13
  • the question is about the memory structure of the `map` being untouched. – Agrudge Amicus Feb 16 '20 at 12:53
  • @AgrudgeAmicus It doesn't matter that the memory structure of the map is untouched, but trying to delete something that is not in the map using the map's `erase()` function results in undefined behaviour. – jignatius Feb 16 '20 at 13:21