Standard containers aren't thread-safe, and they aren't specified to have "fail fast" iterators in the Java sense. So there are at least two things that can go wrong with unprotected concurrent access:
- a data race on the container, which is undefined behavior
- one thread invalidates an iterator and later another thread uses an equal-valued iterator. This is also undefined behavior but it isn't necessarily a data race, and would be a bug in a single-threaded program too. It's just a bit easier to lose track of multiple iterators on the same container when they're used in different threads.
One might say that the C++ philosophy is to "succeed fast", and never mind what happens when the programmer fails ;-). Hence there are no built-in locks that would be redundant for many users. Instead it's your problem -- you'd rather be unhappy that the locks are slowing down this program, than unhappy that they're slowing down this program and every other program you ever wrote that used set, even when the set isn't concurrently accessed.
writing operations are not often and reading operation very often.
That's exactly the situation where reader-writer locks should perform well. The only way you can improve your situation is if you can reduce the write operations from "not often" to "never", which presumably you can't.