1

I am designing and entity-component system for a project, and C++ memory management is giving me a few issues. I just want to make sure my design is legitimate.

So to start I have an Entity class which stores a vector of Components:

class Entity
{
    private: 
        std::vector<std::unique_ptr<Component> > components;
    public:
        Entity() { };
        void AddComponent(Component* component)
        {
            this -> components.push_back(std::unique_ptr<Component>(component));
        }
        ~Entity();
};

Which if I am not mistaken means that when the destructor is called (even the default, compiler created one), the destructor for the Entity, will call ~components, which will call ~std::unique_ptr for each element in the vector, and lead to the destruction of each Component, which is what I want.

The component class has virtual methods, but the important part is its constructor:

Component::Component(Entity parent)
{
    parent.addComponent(this)  // I am not sure if this would work like I expect
    // Other things here
}

As long as passing this to the method works, this also does what I want. My confusion is in the factory. What I want to do is something along the lines of:

std::shared_ptr<Entity> createEntity()
{
    std::shared_ptr<Entity> entityPtr(new Entity());
    new Component(*parent);
    // Initialize more, and other types of Components
    return entityPtr;
}

Now, I believe that this setup will leave the ownership of the Component in the hands of its Parent Entity, which is what I want. First a small question, do I need to pass the entity into the Component constructor by reference or pointer or something? If I understand C++, it would pass by value, which means it gets copied, and the copied entity would die at the end of the constructor.

The second, and main question is that code based on this sample will not compile. The complete error is too large to print here, however I think I know somewhat of what is going on. The compiler's error says I can't delete an incomplete type. My Component class has a purely virtual destructor with an implementation:

inline Component::~Component() { };

at the end of the header. However since the whole point is that Component is actually an interface. I know from here that a complete type is required for unique_ptr destruction. The question is, how do I work around this? For reference I am using gcc 4.4.6.

Community
  • 1
  • 1
Godric Seer
  • 359
  • 4
  • 16

1 Answers1

2
Component::Component(Entity parent)

takes parent by calue so you add the component to this temporary, that will go away at end of function. And the original will miss this call. try

Component::Component(Entity &parent)

For the other part, you must ensure the type is complete where the template is instantiated. The usual way is to declare the dtor in class as you do, and just put the implementation in the .cpp where the required types are defined. Inline is not really necessary. Or you could include the other header before Entity, if in will not cause circular includes.

Balog Pal
  • 16,195
  • 2
  • 23
  • 37
  • Changing the signature won't solve OP's problem. They're passing ownership of `this` to a `unique_ptr`. – jrok Jun 30 '13 at 22:18
  • @jrok: elaborate please? Yes, Component is just created with new, and implicitly passing its ownership to the "parent" entity. Which problem is not solved? (I assume the last block meant *entityPtr as param really) – Balog Pal Jun 30 '13 at 22:27
  • Okay, i got it sorted out. Ended up that I was also storing the parent (for future message passing) inside the component. I was attempting to copy the Entity, which then resulted in the unique_ptrs trying to be copied. The fix to the first part actually fixed the second as well. – Godric Seer Jun 30 '13 at 22:57