Jump to content
  • Advertisement

Archived

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

DerekSaw

std::map with overloaded operator [ ]?

This topic is 5889 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

Let''s say I have
std::map<std::string,std::string> amap;
...
str = amap["ID_ABC"];
 
...so consider I know the n-th position of "ID_ABC", say 1, may I do this:
str = amap[1]; 
If cannot, which is the best way? Wrap the std::map and provide an operator[int] ? OR Overload the operator[] on the map<string,string> ? (which I think may not a good way) Any suggestion?

Share this post


Link to post
Share on other sites
Advertisement
A map does not guarantee that its data is stored in contiguous fashion, so you can''t "offset" into it. Wrapping it isn''t efficient either, as your wrapper will end up either having to iterate or maintain an internal conversion table. If you wanted integer lookup, you should have declared the map with an integer key type.

If you''re concerned about speed, take a look at std::hash_map (SGI and STLPort provide this; Dinkum doesn''t with MSVC6 though MSVC.Net has them).

Share this post


Link to post
Share on other sites
if you use a std::map and declare it

using namespace std;

map<string,string>

you cannot access the [] operator with anything other than a string.

It has to do with the way maps are implemented. As red-black b-trees, they aren''t necessarily stored in order. Indeed, the arrangement of the tree shifts, sometimes dramatically, on every insertion or deletion.

You really shouldn''t access an element of a map in any other way than with the key type that the map is declared with.

if you have a map<int,string> you can treat is as a sparse array, doing things like

my_map[0] = "blah";
my_map[100] = "200";

takes only 2 elements worth of memory, whereas with a vector, you''d be allocating 100 elements worth of mem.

but if you do a map<string,string>, don''t try to access it like my_map[0] or my_map[100]

Share this post


Link to post
Share on other sites
thanks guys.
Actually, my office is using MSVC5 ! So I assume that it is too old to actually compile STLPort flawlessly.

dearid, you gave me an idea... creating a class with two maps, one is <int,string>, another is map<string,string>... and overload operator[int] and operator[string].... since speed is not the concern over here.... any more tips/hints/suggestions are welcomed!

... oh man... GameDev.Net forums are damn helpful!

Share this post


Link to post
Share on other sites
quote:
Original post by DerekSaw
Actually, my office is using MSVC5 ! So I assume that it is too old to actually compile STLPort flawlessly.

I''m not so sure about that. MSVC5 was the first version to provide the basic functionality necessary to compile the STL without platform-specific hacks, IIRC. Check the STLPort website for more info.

quote:

daerid, you gave me an idea... creating a class with two maps, one is map<int,string>, another is map<string,string>... and overload operator[int] and operator[string].... since speed is not the concern over here.... any more tips/hints/suggestions are welcomed!

The real question is what are you trying to achieve? There may be much better ways to accomplish whatever you have in mind.

Share this post


Link to post
Share on other sites
I''m trying to simulate a row (or record) in a database table. e.g.

userid = record["user_id"]; // obtaining the field named "user_id"
// OR
userid = record[0]; // obtaining the 1st field




p/s: i''m storing all the fields'' data as strings.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Í don''t remember this


struct key_type
{
key_type():cmd_int(false) {}
key_type(const std::string s):cmd_int(false),str(s) {}
key_type(int i):cmd_int(true), idx(i) {}
key_type(const std::string s, int i):cmd_int(false),str(s),idx(i) {}


bool cmd_int;
std::string str;
int idx;
bool operator < (const key_type & k) const
{
if(cmd_int || k.cmd_int)
return idx < k.idx;
return str < k.str;
}
}


This should work, I''ve not tested, since operator[] takes a const reference to the key type and this allows implicit construction of a temporary using the single param constructor.

Share this post


Link to post
Share on other sites
AP:
That still doesn''t provide natural semantics for operator []; one can''t directly use a string or integer as index.

quote:
Original post by DerekSaw
I''m trying to simulate a row (or record) in a database table.
<example omitted>


class Record
{
public:
Record();
Record( const Record & r );
Record( std::vector< std::string > & column_headings );
 
bool InsertColumn( const std::string & heading, const int index );
const std::string & operator [] ( int index ) const;
const std::string & operator [] ( const std::string & heading ) const;
 
private:
std::map< std::string, std::string > m_columns;
std::vector< std::string > m_headings;
};

m_headings would contain the column headings in the order in which you would like them referenced. m_columns would contain the actual data, associated with the string headings (remember, maps have no concept of "ordering").

const std::string & Record::operator [] ( int index ) const
{
if( index < m_headings.size() )
return m_columns[ m_headings[index] ];
 
return "Out of bounds";
}
 
const std:;string & Record::operator [] ( const std::string & heading ) const
{
static std::map< std::string, std::string >::iterator iter = 0;
 
iter = m_columns.find( heading );
if( iter == m_columns.end() )
return "Invalid heading";
 
return *iter;
}

Using these two version of operator [], you can now obtain record data with natural syntax using both integers and strings as indices.

Note the three constructors (default, copy and initializer). The third version takes a vector of headings in the order you want them to be referenced when accessed by integer index. After initializing your record, the order of columns must be preserved (or operations will quickly turn to mush), so we provide the InsertColumn method:

bool Record::InsertColumn( const std::string & heading, const int index )
{
if( m_columns.find( heading ) == m_columns.end() )
{
m_headings.insert( index + 1, heading );
m_columns[ heading ] = "";
return true;
}
 
return false;
}

Enjoy!

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
are you just looping through everything in the map? Look up iterators!

Share this post


Link to post
Share on other sites

  • Advertisement
×

Important Information

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

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!