Sign in to follow this  
Genjix

adding anonymous maps to std::map

Recommended Posts

Genjix    100
any suggestions on how i could do something like this
	map<string , int> si;
	si[""] = 10;
	si[""] = 22;
	si[""] = 33;

	for(map<string , int>::iterator it = si.begin() ; it != si.end() ; it++)
	{
		cout << it->first << " = (" << it->second << ")\n";
	}

i've thought of 4 solutions
  1. having a function to generate a random string of say 16 byte length (P(same) = 1/(256^16))
  2. making a wrapper class - which would mean i would have to re-implement all operators and functions.
  3. just always use a vec_myobj and map_myobj and if named add to map, else add to vector.
  4. the best solution i've come up with code wise is to wrap all data in a structure, with a string name variable. when doing a lookup, you skip all empty strings. But then you lose all the benefits of std::map's name lookup speed.
Any ideas?

Share this post


Link to post
Share on other sites
snk_kid    1312
std::map is a model of a unique associative container, meaning that no two elements have the same key.

For std::string the comparator used for std;:map defaults to using std::less<std::string> which use std::string overloaded less than operator which does a lexicographical compare meaning that 2 strings that are empty strings i.e. "" are the same key.

You should not change the meaning of that if you do not want to go into the land of undefined behaviour. If you want multiples of the same keys then use std::multimap or std::tr1::unordered_multimap (old name hash_multimap) e.g:


#include <algorithm>
#include <map>
#include <string>
#include <iostream>

typedef std::multimap<std::string , int> mm;

void print(const mm::value_type& p) {
std::cout << p.first << " = (" << p.second << ")\n";
}

int main() {

mm si;

si.insert(mm::value_type("", 10));
si.insert(mm::value_type("", 22));
si.insert(mm::value_type("", 33));

std::for_each(si.begin(), si.end(), print);

}


But really why you would you want to do such a thing is beyond me, is there some specific reason? I ask because we could probably find a much better solution/design to the problem.

Share this post


Link to post
Share on other sites
Genjix    100
well, i have a scene created, and when 1000+ objects are created, it seems inappropriate to have handles for every single one (handles being what i use to interact with specific objects through event handlers). so i need some anonymous way to store objects, sometimes with or without a key. i don't know whether i should just use the map and vector idea.

Share this post


Link to post
Share on other sites
Drew_Benton    1861
[edit] And I just realized this is exactly what snk_kid has said [sad]. Oh well, I second his suggestion with some more code [grin]

Quote:
Original post by Genjix
well, i have a scene created, and when 1000+ objects are created, it seems inappropriate to have handles for every single one (handles being what i use to interact with specific objects through event handlers). so i need some anonymous way to store objects, sometimes with or without a key. i don't know whether i should just use the map and vector idea.


Right now I am working with an idea similar to this for self managing objects. However, my problem was name collisions, to which I have resolved, not inserting in elements w/o a name. However, here is an example of what you could do it - it is pretty much along the lines of what I am using and it is working so far. I use a mutlimap to take care of the problem:


std::multimap<std::string , int> si;

void AddNumber( int val )
{
std::pair<std::string,int> p1( "", val);
si.insert( si.end(), p1);
}

void AddNumber( std::string name, int val )
{
std::pair<std::string,int> p1( name, val);
si.insert( si.end(), p1);
}

void GetNumbers( std::string name, std::vector<int> &numbers )
{
std::multimap<std::string , int>::iterator itr = si.find( name );
if( itr == si.end() )
return;
for( int x=0;x<si.count( name );x++ )
{
numbers.push_back( itr->second );
itr++;
}
}

void GetNumbers( std::vector<int> &numbers )
{
std::multimap<std::string , int>::iterator itr = si.begin();
if( itr == si.end() )
return;
for( itr;itr != si.end(); itr++ )
{
if( itr->first.size() != 0)
numbers.push_back( itr->second );
}
}

int main(int argc, char* argv[])
{
AddNumber(10);
AddNumber(22);
AddNumber(33);

AddNumber( "Degrees", 360 );
AddNumber( "Degrees", 180 );

std::cout << "Numbers without names: " << std::endl;
std::vector<int> NoNames;
GetNumbers( "", NoNames );
for( int x=0;x<NoNames.size(); x++ )
{
std::cout << NoNames[x] << "\n";
}
std::cout << std::endl;

std::cout << "Numbers with names: " << std::endl;
std::vector<int> Names;
GetNumbers( Names );
for( int x=0;x<Names.size();x++)
{
std::cout << Names[x] << "\n";
}

return 0;
}







There is a lot of room for expansion as to what you can do, the your imagination flow [wink]. What I took advantage of is I can use the & reference to a vector and pass in one vector to multiple functions that get objects to end up with one list that has all of them in it. Very useful!

- Drew

[Edited by - Drew_Benton on March 27, 2005 12:57:29 PM]

Share this post


Link to post
Share on other sites
Genjix    100
cool thanks, you've given me the idea to do what you're doing but instead override the insert methods (disabling multiple objects, when there is a string). Thanks, very much!

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this