views:

105

answers:

2

I have a problem with what appears to be some sort of implicit casting to const when I use iterators. I'm not really sure which code is relevant (if I did I probably wouldn't be asking this question!) so I will try my best to illustrate my problem.

typedef set<SmallObject> Container;              //not const

void LargeObject::someFunction() {               //not const
    Container::iterator it;                      //not const
    for (it = c.begin(); it != c.end(); ++it) {  //assume c is a "Container"
        (*it).smallObjectFunction();             //not a const function
    }
}

However I always get the following error:

error: passing 'const SmallObject' as 'this' argument of 'int SmallObject::smallObjectFunction()' discards qualifiers

However, if I cast it as ((SmallObject)(*it).smallObjectFunction(); then I get rid of the error message.

The only thing I can figure is that somehow the definition of

bool operator< (const SmallObject &a) const;

is somehow causing the iterator to return const objects. Any help or explanation here?

+10  A: 

Sets and maps keep the elements in order according to the sort condition. For user code not to break invariants, the key of the map and the whole element in the set must be constant. Your problem is that the stored element is not a SmallObject but a const SmallObject.

If this was not limited you could have:

int init[] = { 1, 2, 3, 4, 5 };
std::set<int> values( init, init+5 );
std::copy( values.begin(), values.end(), 
   std::ostream_iterator<int>(std::cout, " "));
   // 1 2 3 4 5
*(values.find(3)) = 5; // luckily this does not work!
std::copy( values.begin(), values.end(), 
   std::ostream_iterator<int>(std::cout, " "));
   // 1 2 5 4 5 -- not in order!!!

The problem there is not only that now the set element would not be in order, but that depending on how the tree was built there could be elements that are present in the set but cannot be found.

David Rodríguez - dribeas
So making smallObjectFunction function const (if you can) will solve the problem
Patrick
I am modifying the objects in some cases of smallObjectFunction. What are my options here? Cast it like I mention (and currently do)? Remove from the set, edit, and insert back in (ugly)? Anything else?
The proper way of doing it is taking the small object out, editing and then inserting. Else you may be breaking the order and the invariants that `set` depends on and you will get unexpected results. If the changes do not affect the order, then you can use a map with the whatever the key is and modify the value --that is not const.
David Rodríguez - dribeas
Couldn't the removing and inserting of objects during iteration cause issues?
Removing elements while iterating will cause issues. There are different ways of handling it, in general take a copy of the iterator, advance it, remove the old copy. Insertion does not invalidate the iterator, so you can insert at any time, but you will probably be better off by keeping the modified elements in a different container and adding them to the set after you have completed the iteration (to avoid visiting the new element). If you follow this path, beware of exceptions that may wind up the stack before the loop ends and you reinsert the elements.
David Rodríguez - dribeas
A: 

The object(s) in your c container are const and the smallObjectFunction tries to modify the object value.

John Paul