Is std::map::end thread-safe and is guaranteed that it always the same for the same container? Is std::map::end thread-safe and is guaranteed that it always the same for the same container? multithreading multithreading

Is std::map::end thread-safe and is guaranteed that it always the same for the same container?


Should I protect std::map::end or is guaranteed that it always the same for one allocated container?

Technically any call to a member function must be protected by a mutex if it could happen concurrently with any non-const member function. So if any thread could be inserting or erasing elements then it's not safe to call end() without locking the mutex.

Can I use something like this static auto const map_it_end = map1.end(); which is not protected by std::mutex?

You can cache the past-the-end iterator in some cases, because the past-the-end iterator for a std::map is not invalidated by insertions and erasures, only potentially by swapping or moving the map.

But why would you want to? The slow operation is find() not end(), so if you call end() while you still hold the mutex then it definitely works.

If other threads could be erasing elements then you need to hold the mutex lock while you dereference the iterator returned by find() to be sure it isn't invalidated by another thread erasing the element it refers to. So again, making a call to end() isn't going to be a problem while you have the mutex locked already.


I find nothing in 23.2 Container requirements that specifies that end() always returns the same value, nor that it is thread safe. end() is defined as follows.

begin() returns an iterator referring to the first element in the container. end() returns an iterator which is the past-the-end value for the container. If the container is empty, then begin() == end();

This specification appears to cover end() for all containers. I find nothing in 23.4.4 Class template map that supercedes this general container requirements. Actually, "Past-the-end value" is worded like that so it can reasonably be interpreted to mean that the value of end() could change depending on what/where is the last element in the container.

And that would be the typical case for a std::vector. A typical std::vector's end() value changes depending on the number of elements in the vector, for the obvious reasons. Nothing specifies that it has to, but that's typically the case. Going back to a std::map, one might expect that a given map's end() will always be same value, but nothing states that it has to, either.

I would say that all access to a std::map must be protected by a mutex. Once a mutex is released, nothing about the map is valid any more. Can't assume that end() will remain a valid iterator, after the mutex gets released.