Problem with adding pointer to std::map

Started by
9 comments, last by Antheus 13 years, 9 months ago
I am implementing a resource pack system into my engine, where you can request resource packs from the resource manager, by giving it the name of the pack. For this I decided to use the std::map container since it makes it easy to get an element by key (in this case the key is the name). I have the following code:

ResourcePack* ResourceManager::getResourcePack(String name){	// See if the pack with this name is already created.	ResourcePack* pack = mResourcePacks[name];	if(!pack)	{		// Not found, create new pack.		pack = new ResourcePack(name);		mResourcePacks.insert(pair<String, ResourcePack*>(name, pack));	}		return pack;}


The problem is that the value of pointer to the newly created resource pack is always zero when it is added to the map. If I run the above code once with the name "test" it creates the pack and adds it to the map. If I put a breakpoint on the return line to see what is inside mResourcePacks it shows me one element with "test" as the value for first and 0x00000000 as the value for second.

mResourcePacks is declared as:

std::map<String, ResourcePack*> mResourcePacks;
and String is just a typedef for std::string. What am I doing wrong here?
Advertisement
Huh, seems that the index operator actually inserts a new element if none with the given name is found. If I change the code to this:

ResourcePack* ResourceManager::getResourcePack(String name){	// See if the pack with this name is already created.	ResourcePack* pack = mResourcePacks[name];	if(!pack)	{		// Not found, create new pack.		pack = new ResourcePack(name);		mResourcePacks[name] = pack;	}		return pack;}


it works. Do you see any problems with this? Eg. is it safe to assume that pack with by zero every time a resource pack is requested for the first time?
map<>::insert() doesn't insert the element if the key type already exists. When you used [] on the map to check if the key was there or not, you implicitly added the element to the map. One option to fix your code:
	// See if the pack with this name is already created.	ResourcePack *& pack = mResourcePacks[name];	if(!pack)	{		// Not found, create new pack.		pack = new ResourcePack(name);	}		return pack;

map<key, T>::operator [](x) is equivalent to (*((insert(make_pair(x, T()))).first)).second. Which means that if the element doesn't exist when you use [], then for a pointer value type, the inserted value will be the null pointer.
Whoa, what's that? A reference to a pointer? Don't think I have seen one before. In any case, thanks for your help!
here's another variation:

	if(!mResourcePacks.count(name))	{		mResourcePacks[name] = new ResourcePack(name);	}


I like SiCrane's better though :)
Why not use map::find() and avoid the complications?
because using find in this case forces two look-ups while SiCrane's only takes one

if(mResourcePacks.find(name) == mResourcePacks.end()) // first look-up{	mResourcePacks[name] = new ResourcePack(name); // second look-up}


Or is there another way to do it with "find"?
Quote:Original post by scope
because using find in this case forces two look-ups while SiCrane's only takes one

*** Source Snippet Removed ***

Or is there another way to do it with "find"?


map<?,?>::iterator i = map.find(x);if (i == map.end()) i = map.insert(i,make_pair(x,y));return i->second;
If you're going to do a lookup followed by a conditional insert you wouldn't want to use find(), instead use lower_bound() and use the result as a hint to the insert() call.
  MapType::iterator itr = m.lower_bound(key);  if (itr == m.end() || itr->first != key) {    value v = new value;    m.insert(itr, MapType::value_type(key, v));    return v;  } else {    return itr->second;  }

This topic is closed to new replies.

Advertisement