problems with stl map iterators

  • Thread starter Christian Christmann
  • Start date
C

Christian Christmann

Hi,

I've some problems with iterators on hashtbales.

My hashtable.h

class HashTable
{
map<int, void*> nhash;
map<int, void*> getNhash();
....
}
----------

My hashtable.cpp:

map<int, void*> HashTable::getNhash() {
return nhash;
}
}
void HashTable::Insert(int ky,void* entr) {
nhash.insert(pair<int, void*>(ky, entr));
}
....

----------

In another class I use this hashtable:

HashTable lNodes;
const std::map<int, void*>::const_iterator begin =
lNodes.getNhash().begin(); const std::map<int, void*>::const_iterator end
= lNodes.getNhash().end(); std::map<int, void*>::const_iterator iter =
begin;

cout << "Size: " << lNodes.getNhash().size() << endl;
while (iter != end)
{
cout << "Key: " << iter->first << endl; ++iter;
}
}


The output:

Size: 3
Key: 0x80a2de0

or

Size: 12
Key: 0x80b8ae8
Key: 0x80b8ee8
Key: 0x80b9170
Key: 0x80b9af0
Key: 0x80bbb68
Key: 0x80bbf68
Key: 0x80bc1f0
Key: 0x80bcb70

There are always some elements missing. Even if the size is 3 just 1
element is printed.
Only with hashtables of size 1 I get the correct output.

What's wrong?

Thank you for your help

Chris
 
L

Larry I Smith

Christian said:
Hi,

I've some problems with iterators on hashtbales.

My hashtable.h

class HashTable
{
map<int, void*> nhash;
map<int, void*> getNhash();
...
}
----------

My hashtable.cpp:

map<int, void*> HashTable::getNhash() {
return nhash;
}
}
void HashTable::Insert(int ky,void* entr) {
nhash.insert(pair<int, void*>(ky, entr));
}
...

----------

In another class I use this hashtable:

HashTable lNodes;
const std::map<int, void*>::const_iterator begin =
lNodes.getNhash().begin(); const std::map<int, void*>::const_iterator end
= lNodes.getNhash().end(); std::map<int, void*>::const_iterator iter =
begin;

cout << "Size: " << lNodes.getNhash().size() << endl;
while (iter != end)
{
cout << "Key: " << iter->first << endl; ++iter;
}
}


The output:

Size: 3
Key: 0x80a2de0

or

Size: 12
Key: 0x80b8ae8
Key: 0x80b8ee8
Key: 0x80b9170
Key: 0x80b9af0
Key: 0x80bbb68
Key: 0x80bbf68
Key: 0x80bc1f0
Key: 0x80bcb70

There are always some elements missing. Even if the size is 3 just 1
element is printed.
Only with hashtables of size 1 I get the correct output.

What's wrong?

Thank you for your help

Chris

Please don't multi-post.

I already answered this in the gnu.g++.help newsgroup.
 
S

simont

Christian said:
Hi,

I've some problems with iterators on hashtbales.

You're not kidding - although they're maps, not hash tables.
My hashtable.h

class HashTable
{
map<int, void*> nhash;
map<int, void*> getNhash();
...
}

You seem to be returning the nhash member by value here, which is
unusual to say the least. This forces a copy to be made each time
getNhash() is called.

As an aside, I'm assuming this summary is slightly wrong, since both
nhash and getNhash() are private ...
----------

My hashtable.cpp:

map<int, void*> HashTable::getNhash() {
return nhash;
}

I'm just going to remove the extra closing curly bracket, but in
general
it is nice if the posted code actually compiles (since you're not
asking
about a compiler error, at least).
void HashTable::Insert(int ky,void* entr) {
nhash.insert(pair<int, void*>(ky, entr));
}
...

----------

In another class I use this hashtable:

HashTable lNodes;
const std::map<int, void*>::const_iterator begin =
lNodes.getNhash().begin(); const std::map<int, void*>::const_iterator end
= lNodes.getNhash().end(); std::map<int, void*>::const_iterator iter =
begin;

Mmm, unreadable goo. With permission, I'm going to reformat that so I
have room to hang my comments.

typedef std::map<int,void*>::const_iterator HashIter;

HashIter begin = lNodes.getNhash().begin();
// make a temporary copy of lNodes' std::map, get the begin iterator
// from it, and then throw that copy away. 'begin' is now an
iterator
// into a destroyed temporary copy of a map.

HashIter end = lNodes.getNhash().end();
// make another temporary copy of lNodes' std::map, get the end
// iterator from this copy, and then throw the copy away. 'end' is
// now an iterator into another destroyed temporary copy of a map.

HashIter iter = begin;
// copy of an iterator pointing to a destroyed temporary map
cout << "Size: " << lNodes.getNhash().size() << endl;

This creates the third temporary copy of lNodes.nhash so far, but at
least it should give the right result.
while (iter != end)
{
cout << "Key: " << iter->first << endl; ++iter;

As soon as you dereference an iterator to a deleted map, you're in
'undefined' territory. Simply getting the wrong result is pretty much
the least catastrophic outcome you could hope for.
}
}


The output:

There are always some elements missing. Even if the size is 3 just 1
element is printed.
Only with hashtables of size 1 I get the correct output.

What's wrong?

In case you haven't spotted it from the comments above yet, the problem
is that you're making temporary copies of the map and then throwing
them
away. These anonymous temporaries get destroyed as soon as you hit the
';' at the end of the statement where they're created, ie, at the end
of
"... lNodes.getNhash() ... ;"

If you want to get the size of, and iterators into, an HashTable's
nhash
member rather than making a copy and using that, you need getNhash() to
return a reference rather than a value. Change
map<int, void*> getNhash();
map<int, void*> HashTable::getNhash()
{
return nhash;
}
to
map<int, void*>& getNhash();
map<int, void*>& HashTable::getNhash()
{
return nhash;
}

and everything will work as you expect. No other changes required.

Especially if you're coming from a language (like Java or Python) that
always passes by reference instead of value [1]: remember that C++
allows you to specify whether your arguments and return values have
reference or value semantics. If you want reference semantics, you
need
to put the '&' in to indicate it.
Thank you for your help

np, hth.

[1] - ok, Java doesn't always pass by reference, just mostly.
 
C

Christian Christmann

Especially if you're coming from a language (like Java or Python) that
always passes by reference instead of value [1]: remember that C++ allows
you to specify whether your arguments and return values have reference or
value semantics. If you want reference semantics, you need
to put the '&' in to indicate it.


Thank you very much for your posting. With your help I could solve
my problem.

Chris
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,904
Latest member
HealthyVisionsCBDPrice

Latest Threads

Top