Archived

This topic is now archived and is closed to further replies.

Ziphnor

The hash_map that lied!

Recommended Posts

Ive know spent almost 2 full days debugging an insane problem. For my game ive been creating a simple window manager, that works similar to the java Swing system. A weird problem seemed to arise when more than one component with a listener existed. The effect being that *all* buttons reacted to input to any one of them. The key players in this weird scenario is : the MListener - a managed pointer to a Listener object the listener has a managed pointer to the component its associated with(accessed by getComponent member function) the MPComponent - a managed poiner to a component (managed pointers are a simple reference counting system) Each managed pointer has a bypass method that returns an int, the real pointer(not to be used lightly!). The hashmap in question has as key a MPComponent, and as value a pointer to a vector of MListener(typedef'ed as ListenerVector), ie the associated listeners. When a listener is to be registered in the window manager, we check to see if the component has any listeners(we get an iterator to it by using find, and then checking that iterator against the iterator gotten by using end(). If these are the same, there is no entry to this component so we make a new listenervector there, and add the listener to be added to this list. On the other hand, if there already is an entry, we dereference it and adds the listener to the already existing listenervector. This is shown below:
      
void addListener(MListener ml)
{
	MPComponent m = ml->getComponent();
	hash_map<MPComponent, ListenerVector >::iterator list = component_listener.find(m);
	hash_map<MPComponent, ListenerVector >::iterator end = component_listener.end();

	if(list != end)
	{
		ListenerVector ls = (*list).second;
		ls->push_back(ml);
	}
	else
	{
		component_listener[m] = new vector<MListener>();
		component_listener[m]->push_back(ml);
	}
	listeners.push_back(ml);
}
   
(note: listeners is just an alternate access method, allowing one to traverse all listeners regardless of component association) Anyway, when this code is actually used, it only reaches the else part once, all other calls acts if the hash_map actually had an entry for the MPComponent, and adds the listener to an already existing list(the one associated with the component belonging to the listener that was first added). So all listeners are added to the same ListenerVector associated with *one* component, and the hash_map happily returns this ListenerVector *no* matter what MPComponent you query for(only NULL doesnt). So when later code finds out that one component has been clicked for example, it innocently queries for the listeners associated with that component, gets *all* listeners returned, and continues to inform each and everyone of them that the mouse has been clicked on their target, in effect clicking *all* components on the screen.... I then tried changing the hash_compare method(which shouldnt make any diffence except in speed) to return the real adress of the MPComponent(100% unique naturally), but it still didnt work. Not trusting the hash_map now, i changed it to a hash_map with an int key, simply using the adress of the component directly instead(in essence, prehashing the key. To my huge surprise this actually *works*! This code is given below:
  
void addListener(MListener ml)
{
	MPComponent m = ml->getComponent();
	int adress = m.bypass();
	hash_map<int, ListenerVector >::iterator list = component_listener.find(adress);
	hash_map<int, ListenerVector >::iterator end = component_listener.end();

	if(list != end)
	{
		ListenerVector ls = (*list).second;
		ls->push_back(ml);
	}
	else
	{
		component_listener[adress] = new vector<MListener>();
		component_listener[adress]->push_back(ml);
	}
	listeners.push_back(ml);
}
      
If anyone actually bothered to read this, i would be happy to be enlightened about what could cause this weird behavior!(but im sticking to the later version for now, im sick of that code!!!) Nice to vent some frustration..... [edited by - ziphnor on July 27, 2002 5:07:15 AM] [edited by - ziphnor on July 27, 2002 5:09:20 AM]

Share this post


Link to post
Share on other sites
I''ve worked with hash_maps before, but the key was always an integer. I haven''t experienced with using a non-integer key. And leave it up to MSDN not to clearly document it; or not document it at all It would be interesting to write a small applet that tests this, because I''m curious as well.

Maybe you will have more success with a regular map.

Share this post


Link to post
Share on other sites
What i find most disturbing is that it didnt even
work *after* i specified the hash_compare myself, like so:

size_t std::hash_compare::operator()(const MPComponent& val) const
{
return val.bypass();
}


I mean, shouldnt this be the same as im doing with the int key??

Perhaps i should try changing to STLPort or something.....

Anyway, it works fine now, and i see little reason to change it, but im frustrated by my ignorance of the reason for this malfunction

Its frustrating debugging something like this, i was through *everything* else that was in any way connected to the windowmanager, checking and rechecking(and actually finding some unrelated bugs!), and then it turns out its not my code thats the problem(or at least it seems so...).

Share this post


Link to post
Share on other sites