Program crashes with STD::map find()

Started by
28 comments, last by nullsquared 16 years, 8 months ago
Quote:Original post by Tokiko
Quote:Are you SURE you want that last line to read like that, and not like this??
    (*_collisionMap)[ second ]->addCollision( new Collision( second ) ); 

Sorry there was a typo with the first collision and it should be passing second. So if I didn't type that wrong, you would be correct :P


Well then you can simplify the code even more...

void CollisionSet::addCollision( GameComponent* component ){    if ( _collisionMap->find( component ) == _collisionMap->end() )         (*_collisionMap)[component] = new CollisionQueue();    (*_collisionMap)[component]->addCollision( new Collision( component ) );}// And you would just call it twice, once for each component... // since they don't depend on one another in the original functionaddCollision( first );addCollision( second );


Quote:
(*_collisionMap)[first] = new CollisionQueue();
Now with this line here. I was going to use that earlier, but I figured that it wouldn't work since you are trying to find the value paired with first, but if that key hasn't been added, how can you make a new collision? So I guess it will insert a new element if it is not found?


Exactly. But you should check for the element first or you would erase the old CollisionQueue, if it already existed.

And I'm with Zahlman... is there a compelling reason to dynamically create a map? You could just use the map as an instance variable, and then you don't have to destroy it later.

my_life:          nop          jmp my_life
[ Keep track of your TDD cycle using "The Death Star" ] [ Verge Video Editor Support Forums ] [ Principles of Verg-o-nomics ] [ "t00t-orials" ]
Advertisement
Quote:Original post by Verg
And I'm with Zahlman... is there a compelling reason to dynamically create a map? You could just use the map as an instance variable, and then you don't have to destroy it later.


This has been brought up a couple times, but I'm still not sure how I can fix this. I thought if you have a map declared in the class as a member, there are no problems with initializing it in the constructor. Can you or someone give me an example of what you would do in this case?

Quote:
void CollisionSet::addCollision( GameComponent* component ){    if ( _collisionMap->find( component ) == _collisionMap->end() )         (*_collisionMap)[component] = new CollisionQueue();    (*_collisionMap)[component]->addCollision( new Collision( component ) );}// And you would just call it twice, once for each component... // since they don't depend on one another in the original functionaddCollision( first );addCollision( second );


I wouldn't be able to simplify it to that. When I make the collision object for the first component, I need to pass the second component so that I know what collided with it. Same goes for the second component - I pass the first one to the collision object. With your code, you would be creating a collision between the component and itself.
Quote:Original post by Tokiko
Quote:Original post by Verg
And I'm with Zahlman... is there a compelling reason to dynamically create a map? You could just use the map as an instance variable, and then you don't have to destroy it later.


This has been brought up a couple times, but I'm still not sure how I can fix this. I thought if you have a map declared in the class as a member, there are no problems with initializing it in the constructor. Can you or someone give me an example of what you would do in this case?


I believe they meant like so:
class YourClass {    std::map<GameComponent*, CollisionQueue*> _collisionMap;    [...]};

The _collisionMap will be allocated on the stack, not the free-store (heap). Thus, no messy allocation/destruction (new/delete).
Ok, so in other words, don't make it a pointer? Because that is the only difference between what I have and what you suggested.
Quote:Original post by Tokiko
Ok, so in other words, don't make it a pointer?
Right - just make it a member variable of the class (as agi_shi's example illustrates).
Quote:Original post by agi_shi
Quote:Original post by Tokiko
Quote:Original post by Verg
And I'm with Zahlman... is there a compelling reason to dynamically create a map? You could just use the map as an instance variable, and then you don't have to destroy it later.


This has been brought up a couple times, but I'm still not sure how I can fix this. I thought if you have a map declared in the class as a member, there are no problems with initializing it in the constructor. Can you or someone give me an example of what you would do in this case?


I believe they meant like so:
class YourClass {    std::map<GameComponent*, CollisionQueue*> _collisionMap;    [...]};

The _collisionMap will be allocated on the stack, not the free-store (heap). Thus, no messy allocation/destruction (new/delete).


Almost [smile]. The _collisionMap will be allocated wherever the "YourClass" instances are allocated. This could either be on the stack or the heap.

However it will be automatically initialised and destroyed (implicitly in the constructor/destructor). Its lifetime is the same as the object that owns it.
Original post by Tokiko
Quote:
Quote:
void CollisionSet::addCollision( GameComponent* component ){    if ( _collisionMap->find( component ) == _collisionMap->end() )         (*_collisionMap)[component] = new CollisionQueue();    (*_collisionMap)[component]->addCollision( new Collision( component ) );}// And you would just call it twice, once for each component... // since they don't depend on one another in the original functionaddCollision( first );addCollision( second );


I wouldn't be able to simplify it to that. When I make the collision object for the first component, I need to pass the second component so that I know what collided with it. Same goes for the second component - I pass the first one to the collision object. With your code, you would be creating a collision between the component and itself.


That code was just a simplification of what you'd already written.

In your previous code there was no interaction between the two objects... they were just parameters in the same function.

If there needed to be interaction, your original code was not doing that.

my_life:          nop          jmp my_life
[ Keep track of your TDD cycle using "The Death Star" ] [ Verge Video Editor Support Forums ] [ Principles of Verg-o-nomics ] [ "t00t-orials" ]
Quote:Original post by Tokiko
Ok, so in other words, don't make it a pointer? Because that is the only difference between what I have and what you suggested.


Yes, that's what "having the map as a member" would mean. As it stands, you have *the pointer* as a member, and allocate an instance.

Disadvantages of going through a pointer:
- You become responsible for deallocating the allocation in the class destructor.
- You become responsible for cloning the allocated thing (unless you are doing some weird copy-on-write scheme, but that's even more work) in the copy constructor and assignment operator (or else disabling them).
- Every time the code looks up something in the map at runtime, it has to go through indirection - it looks up the pointer from the class' structure, dereferences the pointer, and then calls a function upon the allocated map. With a map held as a member, it's "right there" and ready to use. Now, in loops, that lookup result will probably get cached, but you can still cause significant degradation of performance this way.
- You pay extra memory: likely 4 bytes for the pointer within the class, and likely another 4 bytes (which you can't even inspect) for the new operator's internal bookkeeping (because you made an allocation).
- Every time you do something with the map, you have to deal with what I like to refer to as "&*&*ing syntax". [wink]

Advantages:
- Storing things by pointer lets you take advantage of polymorphism (you can't make a virtual call through a value, because it uses the static type of the value for that call). But std::map isn't polymorphic.
- Storing things by pointer lets you share them between instances, but you have to be really careful about when things are deleted when you do that (or use a smart pointer, such as boost::shared_ptr). Anyway, that doesn't seem to be what you want here.
- If you use boost::shared_ptr, you might get a performance benefit when storing instances of your class in a std::vector (since when the vector resizes, the pointed-at maps will be left as-is instead of being copied along with the structure, so less total data is shuffled).

You're assuming extra responsibility, quite a bit of extra work, a cost in total memory, and a likely performance cost for using the struct; in exchange for access to polymorphism (unused), access to sharing objects (probably unused and also tricky anyway), and a possible performance boost when storing the struct. I'd say that's a pretty bad trade-off.
Quote:
void CollisionSet::addCollision( GameComponent* component ){    if ( _collisionMap->find( component ) == _collisionMap->end() )         (*_collisionMap)[component] = new CollisionQueue();    (*_collisionMap)[component]->addCollision( new Collision( component ) );}// And you would just call it twice, once for each component... // since they don't depend on one another in the original functionaddCollision( first );addCollision( second );


It's possible that this is what you wanted to do:

void CollisionSet::addCollision( GameComponent* first, GameComponent *second ){    if ( _collisionMap->find( first ) == _collisionMap->end() )         (*_collisionMap)[first] = new CollisionQueue();    (*_collisionMap)[first]->addCollision( new Collision( second ) );}addCollision( first , second );addCollision( second , first );


Your original code wasn't doing that. Neither "GameComponent" was interacting.
my_life:          nop          jmp my_life
[ Keep track of your TDD cycle using "The Death Star" ] [ Verge Video Editor Support Forums ] [ Principles of Verg-o-nomics ] [ "t00t-orials" ]
Quote:Original post by rip-off
Quote:Original post by agi_shi
Quote:Original post by Tokiko
Quote:Original post by Verg
And I'm with Zahlman... is there a compelling reason to dynamically create a map? You could just use the map as an instance variable, and then you don't have to destroy it later.


This has been brought up a couple times, but I'm still not sure how I can fix this. I thought if you have a map declared in the class as a member, there are no problems with initializing it in the constructor. Can you or someone give me an example of what you would do in this case?


I believe they meant like so:
class YourClass {    std::map<GameComponent*, CollisionQueue*> _collisionMap;    [...]};

The _collisionMap will be allocated on the stack, not the free-store (heap). Thus, no messy allocation/destruction (new/delete).


Almost [smile]. The _collisionMap will be allocated wherever the "YourClass" instances are allocated. This could either be on the stack or the heap.

However it will be automatically initialised and destroyed (implicitly in the constructor/destructor). Its lifetime is the same as the object that owns it.


Oh, good point, silly me. [embarrass] I think that's what I was trying to say, just sort of wrote it out wrong...

This topic is closed to new replies.

Advertisement