Jump to content
  • Advertisement
Sign in to follow this  
GuyWithBeard

Problem with adding pointer to std::map

This topic is 2902 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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?

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
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;

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
here's another variation:


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



I like SiCrane's better though :)

Share this post


Link to post
Share on other sites
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"?

Share this post


Link to post
Share on other sites
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;

Share this post


Link to post
Share on other sites
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;
}

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!