For testing purposes I created a little unordered_set and tried to iterate over the set. The set holds an own class:
class Student {
private:
int matrNr;
string name;
public:
Student( const int& matrNr = 0, const string& name = "" )
: matrNr( matrNr ), name( name ) {}
void setNr( const int& matrNr ) {
this->matrNr = matrNr;
}
...
};
I inserted some elements and tried to change the objects during iteration:
unordered_set<Student, meinHash> meineHashTable;
meineHashTable.emplace( 12, "Fred" );
meineHashTable.emplace( 22, "Barney" );
meineHashTable.emplace( 33, "Wilma" );
for (int i = 0; i < meineHashTable.bucket_count(); i++) {
cout << "Bucketnummer: " << i << endl;
unordered_set<Student, meinHash>::local_iterator iter; // not constant?!?
if (meineHashTable.bucket_size( i ) > 0) {
for (iter = meineHashTable.begin( i ); iter != meineHashTable.end( i ); iter++) {
//const_cast<Student&>(*iter).setNr( 1234 ); //This does work
iter->setNr( 1234 ); //This does not work
}
}
else {
cout << "An empty Bucket" << endl;
}
}
I used a local_iterator (and not the const_local_iterator) but still I can't change the objects. For some reasons the iterator refers still to a constant object.
My question now: why is this so? If the normal iterator refers to a const object, what is the different between the const and the non-const iterator?
Tested with VisualStudio 2013 and minGW.
Thanks in advance for any help :-)
EDIT: The Hash functor:
struct meinHash {
size_t operator()( const Student& s ) {
return s.getNr();
}
};
For finders of this topic in the future who have the same question, here is some example output if you change the matrNr with violent:
const_cast<Student&>(*iter).setNr( 5 );
and try to display it:
unordered_set<Student, meinHash>::local_iterator iter = meineHashTable.find( 5 );
iter->display();
you may get something like:
Bucketnummer: 0
An empty Bucket
Bucketnummer: 1
Matrikelnummer: 5
Name: Wilma
Bucketnummer: 2
An empty Bucket
Bucketnummer: 3
An empty Bucket
Bucketnummer: 4
Matrikelnummer: 5
Name: Fred
Bucketnummer: 5
An empty Bucket
Bucketnummer: 6
Matrikelnummer: 5
Name: Barney
Bucketnummer: 7
An empty Bucket
//The not wanted output ;-)
Matrikelnummer: -842150451
Name:
Both set
and unordered_set
have read-only keys. It's easy to see why this is the case - if the key value were to change, the data structure would have it filed in the wrong spot and you wouldn't be able to find it anymore.
Per your example, suppose your hash function simply returned the matrNr
field. When the hash number changes, any lookup for 1234
will fail because there's nothing stored in that hash bucket.
It could be possible to change some part of the object that is not used in making the hash key, but that would lead to possible hard to track down bugs. The standards committee decided to eliminate that possibility by making the entire key const.
There are two ways around this restriction. The first is to split the key from the value and use a map
or unordered_map
instead. The second is to remove the item from the set and reinsert it after it's modified.