Mick
Mick

Reputation: 109

When would you use a vector of shared pointers and when would you use a vector of just plain objects?

I have a quick question.

I started learning C++ a while ago and have always used vectors with shared pointers of objects in them. Or at least smart pointers.

I'm currently programming a game and I was thinking about why I would use smart pointers.

Assume I have a Game class and it has a vector of players.

When would I want to choose for vector<Player> players and when would i want to choose for vector<shared_ptr<Player>>?

Upvotes: 2

Views: 1242

Answers (1)

cmdLP
cmdLP

Reputation: 1856

  1. Use shared_ptrs if the state of the entities is accessed other than in the vector. Also if you make an event-loop, with events like "player collided with other entity". You need to copy a pointer/reference, else you cannot change the state of the entities.

  2. Another important thing is when the entity dies but an event with the entity is not handled, so the entity is deleted from the vector. When you use shared_ptr, the entity lives further, until the event in the eventqueue is deleted. When you store the whole player in the vector, the pointer stored in the event-object is not pointing to the correct entity anymore, if the vector changes its size. When you use a shared_ptr, the entity can be used normally, even if it is not existing in the vector anymore. But it is better to use std::weak_ptr in the event, that the entity is deleted, when it is dead, weak_ptr can check if the pointer is a dangling pointer which means the entity is dead and no event needs to be handled.

  3. Using levels/dimensions, in which the vector of entities lives: When some entity goes to another level, the entity needs to be moved to that level, copying the whole struct is not the best idea. So the best idea is to use some pointer type like shared_ptr, but I recommend to std::move the shared_ptr to reduce reference counting overhead. With std::move the shared_ptr is as fast as a raw ptr.

  4. Virtual classes of entities: When you are writing a game in a 2D or 3D world, you want to store many entities of different kind in the vector, you must use some pointertype to refer to the object, because the entities may have different size.

  5. Fixed player count: If you are programming a game with fixed count of players like a card-game, you do not move the players nor you delete one (however you can just set a flag to indicate that the player is dead and you do not need to erase the entity from the vector), the best way is to use std::vector<Player>.

I think, using shared_ptr living in the vector and with weak_ptrs referencing in events is the best way to manage entities. While weak_ptr(the faster way) does not keep the memory of the Entity alive, the pointer needs to be checked every time.

Some pseudo code

if(fixed count of players
            && there are no other entities
            && there are no virtual subclasses of Player) {
    class Player { ... };

    using player_collection = std::vector<Player>;
    using reference_to_player = Player*;
} else {
    class Entity { public: ... virtual ~Entity(); };
    class Player: public Entity { ... };

    using entity_collection = std::vector<std::shared_ptr<Entity>>;
    using reference_to_entity = std::weak_ptr<Entity>;
};

Upvotes: 2

Related Questions