Skip to main content
gamedev.net
🔒 Locked

std::map push_back?

Started by Genjix Apr 10, 2005 at 5:56 AM 13 replies 12.2k views
Original Post
Genjix
Genjix
is there any way i can do a simple push_back on an std::map without using []? (because the objects don't have < and > implemented - would that be a problem with maps internal ordering?)
Genjix
Genjix
thanks :(
Extrarius
Extrarius
The object doesn't need to have it's own operators, that is what the traits template argument is for - you can make a comparison class to compare them however you want.
"Walk not the trodden path, for it has borne it's burden." -John, Flying Monk
Rob Loach
Rob Loach
Why would you need that? Using the [] operator works very well for insertion. All you have to do is make sure you use the map's key inside the [].
Rob Loach [Website] [Projects] [
Agony
Agony
What is the key for the map in this case? Only the key needs to be orderable. The value that is associated with the key can be anything, and doesn't need to be orderable.
"We should have a great fewer disputes in the world if words were taken for what they are, the signs of our ideas nly, and not for things themselves." - John Locke o
sjelkjd
sjelkjd
You might want to consider hash_map if you don't need your keys to be sorted.
MaulingMonkey
MaulingMonkey
Quote:
Original post by sjelkjd
You might want to consider hash_map if you don't need your keys to be sorted.


Assuming you're willing to rely on that SGI-specific extension.

OP: It dosn't really matter if the sorting makes any logical sense, just that it works (by which I do mean actually works, not stubbed out), if you want to insert into a map. Example:

struct vertex{    double x,y,z;    bool operator<( const vertex & other ) const    {        return (x < other.x) || (y < other.y) || (z < other.z);    }    bool operator==( const vertex & other ) const    {        return (x == other.x) && (y == other.y) && (z == other.z);    }};struct triangle{    vertex points[3];    //alternative: boost::array< vertex , 3 > points;    bool operator<( const triangle & other ) const    {        return (points[0] < other.points[0]) || (points[1] < other.points[1]) || (points[2] < other.points[2]);        //alternative, with boost::array:        //return points < other.points;    }    bool operator==( const triangle & other ) const    {        return (points[0] == other.points[0]) && (points[1] == other.points[1]) && (points[2] == other.points[2]);        //alternative, with boost::array:        //return points == other.points;    }};std::set< vertex > verticies;std::set< triangle > triangles;


(set<> has the same sorting requirements that map<> does)

Of note is I'm a very lazy bum who only implements < and ==. If you want to have the rest implemented, use Boost Operators, but for at least my implementation of the standard library, this is all you need (I think there might be a standard requirement that these be the only requirements for sorting, but my brain fails to recall with any certanty this).
Drew_Benton
Drew_Benton
Can't you just do this?

struct tMyStruct{   int ID;   double value;};std::map< std::string, tMyStruct > MyStructList;int main( int argc, char* argv[] ){	tMyStruct Obj1;    MyStructList.insert( MyStructList.end(), std::pair<std::string, tMyStruct>( "SomeStringNameHere", Obj1 ) );}


That compiled for me on Dev 4.9.9.2 as well as VS7.

If you wanted to really obtain a push_back, you could use the multimap:

struct tMyStruct{   int ID;   double value;};std::multimap< std::string, tMyStruct > MyStructList;int main( int argc, char* argv[] ){	tMyStruct Obj1;    MyStructList.insert( MyStructList.end(), std::pair<std::string, tMyStruct>( "zzzzzzzzzz", Obj1 ) );}


As long as no object had a name with "zzzzzzzzzz" with anyother z's, they would always be added to the end. What I did before on a post, was wrap all this into a function. Don't know where it went so I'll mane a nother example and add it here.


Ok here's another example (done in dev) using just map:
#include <cstdlib>#include <iostream>#include <string>#include <map>struct tMyStruct{   tMyStruct( int id, double val)   {      ID = id;      value = val;   }   int ID;   double value;};std::map< std::string, tMyStruct* > MyStructList;void Push_Back( tMyStruct *item ){     static std::string current = "zzzzz";     MyStructList.insert( MyStructList.end(), std::pair<std::string, tMyStruct*>( current, item ) );     current += "z";}int main( int argc, char* argv[] ){	tMyStruct *Obj1 = new tMyStruct(25,3.14);	tMyStruct *Obj2 = new tMyStruct(-56,2.81);	Push_Back( Obj1 );	Push_Back( Obj2 );		std::multimap< std::string, tMyStruct* >::iterator itr;	for( itr = MyStructList.begin(); itr != MyStructList.end(); itr++ )	{         std::cout << "ID: " <<itr->second->ID << std::endl;         std::cout << "value: " <<itr->second->value << std::endl;    }		// Free up memory at the end	for( itr = MyStructList.begin(); itr != MyStructList.end(); itr++ )	{         delete itr->second;    }    system("pause");}


Don't know if this can be considered 'simple' anymore [wink].

[Edited by - Drew_Benton on April 10, 2005 2:20:15 PM]
Extrarius
Extrarius
Drew_Benton: The thing is that you're using a string as the key, which has relational operators defined. The OP seems to want to use something as the map key that doesn't have proper relational operators. The only real ways around that (that I know of) are to use a different data type or to find some way to implement the operators (as part of the object or as a different comparator for the map's traits parameter).
"Walk not the trodden path, for it has borne it's burden." -John, Flying Monk
Drew_Benton
Drew_Benton
Ohh I see, thanks for clearing that up Extrarius. I just use std::map with a std::string as the key so much, I think I've adopted that as its official use now [grin].
Genjix
Genjix
i have a solution... a vector of pairs?
Agony
Agony
A vector of pairs would probably work, though the performance would probably be lower, and you'd have to manually write a bit more code to get the same functionality. And it does depend on what you're really trying to accomplish. If you want identical functionality to a std::map, then you're going to need some sort of ordering defined anyway. I'm still curious what your types are. A vector of pairs of what? The key needs to be sortable for a map, but the associated value doesn't. And also, as MaulingMonkey said, it doesn't matter if the ordering makes sense or not. Just that there is a strict ordering, such that for any two non-identical instances, one of them is guaranteed to be less than the other. And you should always be able to create some comparison that guarantees this, doesn't matter if it's arbitrary.
"We should have a great fewer disputes in the world if words were taken for what they are, the signs of our ideas nly, and not for things themselves." - John Locke o
Genjix
Genjix
maybe I'll do something like sum of all internal ints so I get the O(log n) lookup speed :)
I'll also have to be careful of collisions ... :/
Agony
Agony
So your key contains a bunch of ints? You could always do a lexical comparison, just like is done on strings. If the number of ints is different between two key instances, then the one with fewer ints is smaller. If they have the same number of ints, then compare the first int. If it is different, the instance containing the smaller int is the smaller object, if it is the same, go on to the next int. Keep doing this all the way through all the ints. Or is the structure arranged such that it's difficult to get a consistent ordering of the ints?
"We should have a great fewer disputes in the world if words were taken for what they are, the signs of our ideas nly, and not for things themselves." - John Locke o

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.