2
votes

I have a question about the std::map iterator behavior. If I understand it correctly, the std::map::const_iterator does not allow to change anything in the container, but std::map::iterator allows to both change the it->second values and the key set (i.e. adding/deleting elements while iterating, etc.). In my situation I need to allow changing the values, but not the key set. I.e. I need something like this:

std::map<int,int>::iterator it=m.begin()
while(it!=m.end())
{
    ++it->second;  // OK: modifying of values is allowed
    if(it->second==1000)
       m.erase(it++); // Error: modifying the container itself is not allowed
    else
       ++it;
}

It seems like the standard iterators do not distinguish between changing the values and changing the container structure. Is there a way to impose this restriction by implementing a custom iterator?

1
I think erase depends only on the constness of the map instance and not of the iterator. - user1781290
have you tried making the container constant? But then how would you add values to it either? - Gasim
The problem is I cannot get a non-const iterator from a constant container. As for your question, adding values to the map can be done in one function and iterating through them in another. This is not a problem, and that's what usually happens in many use cases. - bkxp
but std::map::iterator allows to both change the it->second values and the key set No, you may never do this. The key is always immutable. - Lightness Races in Orbit
"If I understand it correctly, the std::map::const_iterator does not allow to change anything in the container" -- this is changed in C++11, a const_iterator can now be used with erase. The principle is that since you need a non-const reference to the container to do this, it doesn't make sense to quibble over the const-ness of the iterator. Also the C++03 interface impedes some perfectly sensible code (pass a const reference to some function that doesn't modify the container itself but that returns an iterator, then use that iterator to erase something). - Steve Jessop

1 Answers

2
votes

To modify the structure (i.e., insert or delete elements) you need access to an instance of the underlying container, not just an iterator.

Therefore, you can achieve what you're asking for by giving the code in question access only to the iterator, not the underlying container.

template <class Iter> 
cant_remove_if(Iter it, Iter end) { 
    while (it != end) {
        ++it->second; // no problem
        if (it->second==1000)
            // no way to even express the concept `m.erase(it++)` here
        else
            ++begin;
    }
}