user1819636
user1819636

Reputation:

How to use STL map?

I have a private field

std::map<std::string, std::multiset<GraphObject*>>* the_Map;

How can I allocate memory for it and insert a GraphObject? Do I have to use the new operator?

the_Map = new map<string,multiset<GraphObject*>>;

And how can I insert a new GraphObject? It's part of a datastructure and I really need a pointer to a map.

Upvotes: 1

Views: 2120

Answers (2)

Omnifarious
Omnifarious

Reputation: 56038

Why you're storing a ::std:multiset of GraphObject *'s is a bit obscure, but lets roll with that.

This is an answer that is really trivially answered by documentation, but there is no question too dumb for StackOverflow, so...

 the_Map = new map<string,multiset<GraphObject*>>;

That is indeed how you allocate memory for your map. It's generally not a good idea to have bare pointers to things lying around, but you insisted, and that's how you do it. That means you will have to remember to delete it at some point as well. And you will have to make sure that the copy construct of the class that holds the pointer does the right thing (and said right thing will be fairly complicated).

You have an interesting problem now. You are storing a multiset in each map entry. Fortunately this multiset will automatically be created and initialized to empty when a previously unknown key is accessed. OTOH, your use of bare pointers means that you have an exception safety problem. It's possible to leak memory if an exception is thrown anywhere along the way. So you have to catch any exceptions and clean up your object:

 GraphObject *tmp = new GraphObject;
 try {
     (*the_Map)[key].insert(tmp);
 } catch (...) {
     delete tmp;
     throw;
 }

The fact your question is so basic makes me question your assertions about needing to use pointers. And I really wonder if you wouldn't rather have a multimap rather than a map from string -> multiset. But, you're adamant about the general form of your data structure. So the above is how you'd use it.

I'll also say that this data structure's copious use of bare pointers is a pretty bad idea. You'll have to write a pretty sophisticated functions to properly deconstruct or copy the whole mess.

Edit: sigh Coding at 4am on a data structure I would never create myself led me to write some very stupid code. The current version is much better. Though this answer is really much better than mine.

Upvotes: 2

Mike Seymour
Mike Seymour

Reputation: 254431

How can I allocate memory for it and insert a GraphObject?

It doesn't want to be a pointer at all; just make the map itself a member of the class and memory allocation will happen automatically.

Correctly inserting an object is rather fiddly, since you're storing pointers there too. If it doesn't need to be a pointer, then storing objects would make your life much easier. If it really does have to be a pointer (e.g. because GraphObject is a polymorphic base class), I would recommend storing smart pointers: std::unique_ptr, or std::tr1::shared_ptr or boost::shared_ptr if you're stuck in the past.

If you really, really need to use raw pointers for some insane reason, then the closest you can get to an exception-safe insertion is probably:

GraphObject * object = new Whatever(...);
try {
    the_Map[key].insert(object);
} catch(...) {
    delete object;
    throw;
}

or if you don't care about the possiblity of memory leaks on insertion failure:

the_Map[key].insert(new Whatever(...));

Also don't forget to delete each object when you remove it; that won't happen automatically.

I really need a pointer to a map.

No you don't. But if you really believe you do, and want to ignore everyone's advice not to, then you'll need an actual map to point to. I would recommend that you make this map a member of the class, so that its lifetime is managed automatically.

If you really want to make life difficult for whoever maintains the code, then I suppose you could allocate one with new. In that case, remember to delete it when you've finished with it; probably in the class destructor. And if you do that, remember the Rule of Three and implement or delete the copy constructor and copy-assignment operator, since the default implementations will do the wrong thing.

Upvotes: 2

Related Questions