Pointer trouble in entity system [Solved]

Started by
2 comments, last by Fiodis 10 years ago

After reading about them, I've been trying to switch over from an OOP setup to using an entity-component system, but I've had some trouble with dependencies. For example, an entity might want to help members of the same team, so when the AI system is doing processing on that entity's components, it needs a list of other entities on the same team. I saw some examples maintained a list of pointers to entities on the same team, so I tried doing something similar: I defined a Group struct that contains a label and a vector of pointers to the entities that make up that Group:


struct Group {
    std::string name;

    std::vector<Entity*> entities;

};

Both Entities and Groups are contained in larger objects called Scenes, which have as part of their constructor:


entList.push_back(Entity());// First entity added to a std::vector<Entity> called entList
    entList[0].entName = std::string("Cam0");



groupList.push_back(Group());//First group added to an std::vector<Group> called groupList

    groupList[0].name = std::string("Cameras");

    groupList[0].entities.push_back(&entList[0])// Hopefully adds a pointer to the first entity in the Scene's entList

This way I can easily and directly access entities in a specific group without having to iterate all the time over ever entity in the entList. The entity list itself seems to be working fine, but I have trouble whenever I try to access entities through the groupList. Code like the following gives me an access violation error:


Scene scn = Scene();
std::cout << "\n" << scn.entList[0].entName;// This works

std::cout << "\n" << scn.groupList[0].entities[0]->entName;// This gives me an access violation

I think there's something wrong with my understanding of pointers. This thread presented a problem similar to mine, with the suggestion that the OP had made a pointer but hadn't initialized it yet. I'm pretty sure I'm initializing it to &entList[0] with the line groupList[0].entities.push_back(&entList[0]); but maybe vectors of pointers work differently. A google search for "C++ vectors of pointers" didn't seem to indicate that, though. push_back ought to copy the given value to a new element at the vector's end, no? So it should be initialized.

In another attempt to debug, I tried making the following change in Scene's initializer:


groupList.push_back(Group());//First group added to an std::vector<Group> called groupList
    groupList[0].name = std::string("Cameras");
    groupList[0].entities.push_back(NULL)// Initialize it to NULL
grouplist[0].entities[0] = &entList[0];// Change it to point to the first entity in the Scene's entList.

Then this runs fine and outputs the text "not null":


if (groupList[0].entities[0] != NULL) std::cout << "not null"

Which makes me think even more that the initialization is going fine, but then why am I still getting an access violation error whenever I try to access that entity's members through the group's pointer list?

Perhaps it's a simple error but it's driving me mad trying to find it; all the tutorials I re-read about pointers convince me I've got the right idea, but somehow I must not.

Advertisement
Modifying your vector of entities (typically inserting new entities) could reallocate the storage of the vector, invalidating all of the pointers in the group. There's also a problem if you remove or insert an entity ahead of where your group member resides, which could leave the pointer pointing to some entity, but no longer the correct one.

Note: if your pointer is no longer valid, it's not going to automatically change to NULL for you. I unfortunately have to debug pointers that are non-null but still totally wrong very often.

As a solution, instead of storing a pointer/reference to a specific memory location, you should store an index into the vector. As long as you dont yourself rearrange the entities within the vector, you are guaranteed that the index of the entity within the vector will remain the same regardless of what the vector does with the actual memory location.

You need to give access to the entity vector for the code that accesses the entity through the index (what before was a pointer/reference) because you now depend on the vector to hand you the entity, wherever in RAM it resides at that moment.

You can still take references/pointers to objects stored in these memory rearranging containers, but you need to be absolutely certain that no operation is done on the container that could move the objects in memory (eg. nothing should be added/removed while you access the object through a raw pointer/reference)

o3o

That was the problem, thanks guys. Since the entity vector and the group vector are both accessed through their parent Scene, giving access to both when I need them shouldn't be a problem. I don't know why I didn't just store indices to start with; I guess I thought there'd be more overhead using the index to access another vector than using a pointer/reference directly. Ah well; wherever the bottleneck is going to be, it's probably not going to be in the difference between entList[groupList[0].entIndex[0]] and groupList[0].entities[0].

Thanks again! smile.png

This topic is closed to new replies.

Advertisement