Avoiding the C++ chicken or egg problem

Started by
25 comments, last by 21st Century Moose 10 years, 10 months ago

How do I avoid having to forward declare (and thus violating the DRY principle) given the following:

World.h


#include "Entity.h"

class Entity;
typedef std::shared_ptr<Entity> Entity_ptr;
typedef unsigned int entity_id;

class World
{
public:
	void add_entity(Entity_ptr entity);
	void remove_entity(entity_id entityId);
};

typedef std::shared_ptr<World> World_ptr;

Entity.h


#include "World.h"

typedef unsigned int entity_id;

class World;
typedef std::shared_ptr<World> World_ptr;

class Entity
{
public:
	World_ptr world() const { return world_; }
	void set_world(World_ptr world) { world_ = world; }
};

typedef std::shared_ptr<Entity> Entity_ptr;

Because each file depends on the other, neither can compile unless I forward declare the class and the typedef for the shared_ptr.

I've not coded with C++ in, oh, about eight years. So I'm a little rusty.

Thanks!

Advertisement
you can use header guards.

also, I make a types.h file, that you can place common defines and forward declares in.
Check out https://www.facebook.com/LiquidGames for some great games made by me on the Playstation Mobile market.

Welcome back to C++, the world's most popular shit pile of a language, where violating good principles is often conflated with getting work done.

No, I'm not bitter.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

Don't create circular references in the first place ;)
Either have worlds know about entities or entities know about worlds and there's no problem. What do those two classes do anyway?

Btw, if they've both got shared_ptrs to each other, then you've got a circular loop of reference counting, so they'll never be deleted automatically (making shared_ptr about as good as a raw pointer).

Worlds contain Entities. Entitys point to worlds. Entities do not own the world, but the world does own the entities.

World contains a container of entities (shared_ptrs if you like, or unique_ptrs). So World.h #includes Entity.h.

Entity contains a raw pointer to the world. Why? It does not own 'World', so a shared_ptr doesn't fit. Further, the lifetime of World is guaranteed to be longer than Entity, so even weak_ptr is unnecessary. Solution? Entity contains a raw pointer to World (or rather, a reference - since it doesn't change worlds later). So Entity.h forward-declares World.

Problem solved! Really not much of a conundrum, in this case, as ownership is clear.

Thanks guys. I think I'll just pass world in to the entity during update. That was the original plan. I was prematurely optimizing by holding the reference in entity. In fact I'm a little embarrassed because you're telling me exactly what I would have told you if you had asked me the same question!
The premature optimization was avoiding passing in the reference to world for each entity... Which is basically free. Duh, Patrick!

Don't create circular references in the first place ;)

This.

You don't have a problem with C++, you've got a problem with your design.

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.

Entity contains a raw pointer to the world. Why? It does not own 'World', so a shared_ptr doesn't fit.

Thanks for that. I didn't think about ownership in the context of shared_ptr. I just thought it was good practice to always use some sort of "managed" pointer.


Btw, if they've both got shared_ptrs to each other, then you've got a circular loop of reference counting, so they'll never be deleted automatically (making shared_ptr about as good as a raw pointer).

Thanks! I didn't think about circular references. I can see that I'm /really/ going to enjoy this C++ excursion...

This topic is closed to new replies.

Advertisement