views:

764

answers:

4

I have a class in C++ with the following member:

map< someEnum, vector<SomeObject*>* > someMap

So I have a map that gives me a vector of objects for each enumeration I have. For the life of me, I cannot understand how C++ is initializing these objects. Does it deep initialize them by default? If not, what do I need to do?

I'm getting segmentation faults no matter how I try to do this (and I have tried everything), so I'm guessing I'm missing something conceptually.


I should note that I tried to use:

map< someEnum, vector<SomeObject*> > someMap

as well and that didn't work as well. In this case, does C++ deep-initialize the vector?

+3  A: 

It looks like the map gives you a pointer to a vector of objects. If you try to use the map via

mymap[MY_ENUM]->push_back(whatever);

before you initialize, you'll get a segfault. You either need to initialize the vector first

mymap[MY_ENUM] = new vector<SomeObject*>;

or, much better, just make the map give you a plain ol' vector

map <someEnum, vector<SomeObject*> > mymap;

When you first call mymap[MY_ENUM], the vector will be default-initialized (with size zero). Is the problem that you're trying to use the entries of the vector before you enlarge it, e.g.,

mymap[MY_ENUM][2] = whatever;

You still need to use push_back or resize, or something that gives you some space.

Jesse Beder
Jesse thanks, I editing my question in response to your answer.
Yuval A
mymap[MY_ENUM][2] = whatever;is still incorrect, you'll be setting 3rd vector<SomeObject*> instance in this case. Correct way to access third element is( *mymap[MY_ENUM] )[2] = whatever;
Tanveer Badar
@Tanveer: Your proposed syntax assumes we continue to use map<SomeEnum, vector<SomeObject*>*>. But Jesse suggests using the much more sensible map<SomeEnum, vector<SomeObject*> > instead, in which case mymap[MY_ENUM][2] is indeed the correct syntax.
j_random_hacker
+1  A: 

You'll get an empty map that can store std::vector*, referenced by someEnum. The empty map will contain NO vectors. It's up to you to create a new vector object (with new is the safest way) and store its pointer in the map.

It might be nitpicking, but if the enums are a fixed (small) size then why a map for them? A simple array will be easier to get your noodle around and likely more space and CPU efficient unless you have sparse population.

C++ can't initialise the content of the map or vectors because it doesn't know what you want to store there.

Adam Hawes
I think a map is a good idea here, so you have a key-indexed vector of sorts. Being small, efficiency issues are not so important.
Gorpik
@Gorpik: Adam's point is that a vector also works as a "key-indexed vector" -- indeed it works much faster and uses less memory -- provided all the keys are small integers.
j_random_hacker
@j: It is only more space efficient if you have dense population, even in smaller sets. I was asuming from 'enum' that there is a dense population and a small set.
Adam Hawes
+7  A: 

The rule is: If an STL container contains pointers to objects, it it does not create objects on heap and assign them to these pointers. If, however, it contains objects themselves, it does call the default constructor of each contained object and thus initialises them.

What you have here is a map containing pointers (no matter what kind). So do not expect the map to make these pointers to point to memory.

Frederick
+2  A: 

You won't get vector's of SomeObject pointers tucked nicely inside that map by just declaring an object.

Instead, you'll have to proceed like this:

map< someEnum, vector< SomeObject* >* > someMap;

someMap [ somevalue ] = new vector< SomeObject* >;

someMap [ somevalue ] -> push_back( new SomeObject );

Your pain won't end just here. You'll need to clean it up properly before the map goes out of scope with something like this.

// Untested code, may not even compile.
for( map< someEnum, vector< SomeObject* >* >::iterator iter = someMap.begin( ) ; iter != someMap.end( ) ; ++i )
{
     for( vector< SomeObject* >::iterator v = iter -> second -> begin( ) ; v != iter -> second -> end( ) ; ++v )
         delete *v;

     delete iter -> second;
}
Tanveer Badar