Pointer To Deleted Object

I'm not sure if I just have some design issues or if I am using C++ incorrectly. Basically, I have an entity manager for all the entities in my game. I also have a camera class that can "follow" a single entity. The camera knows what entity to follow by using a pointer to it.

The problem is when my entity manager needs to destroy the entity that the camera is following. The entity manager does not use the pointer the camera has to the target entity, but instead searches it's own list. I destroy the entity by first calling delete on it, and then remove it from the std::list that contains all of the entities in the entity manager. When the camera needs to follow the entity, it checks if the entity pointer is NULL before proceeding. Well, the pointer is not NULL, and it is not a bad pointer either because I can access it's data without a problem. It just has a bunch of uninitialized data in it.

So my question is: what is the entity pointer in my camera class pointing to after I delete the actual entity in the entity manager? Do I need some system to tell the camera to make it's target entity (what it follows) NULL?
Last edited on
I think I might just have to use the shared pointer thing from Boost, but I was wondering if there is a way to make all pointers to the deleted object NULL?
When the camera needs to follow the entity, it checks if the entity pointer is NULL before proceeding. Well, the pointer is not NULL,

Pointers don't become NULL when the object they point to is destroyed. That doesn't even happen for the pointer you call delete on, much less for some other pointer floating around in memory somewhere.

and it is not a bad pointer either because I can access it's data without a problem. It just has a bunch of uninitialized data in it.

That doesn't say much. Dereferencing an invalid pointer doesn't always result in a crash. It'll only happen if the memory page the object was located in was already given back to the OS by the application. However, that won't happen if there are still other objects in that page, if the memory was already assigned to another object or if the application simply decides to keep the memory around for future use.

Do I need some system to tell the camera to make it's target entity (what it follows) NULL?

Yes. Said system is called smart pointers. That brings us back to an earlier comment:
I destroy the entity by first calling delete on it, and then remove it from the std::list

...this is trouble. If you find yourself using delete at all, it's usually an indicator that you did something seriously wrong. This system is fragile. It is very easy to forget a delete somewhere or perform it twice - and when an exception is thrown, everything will be in shambles anyway. There are some approaches to the problem:
1. use a list<shared_ptr<CEntity> >
2. use a boost::ptr_list<CEntity*> (or any other ptr_list implementation)
3. C++11 only: use a list<unique_ptr<CEntity>>

In this case it will be 1., because you need shared_ptr in order to use weak_ptr.
weak_ptrs are used when you need to "link" to an object, but you don't own it. This is true for the camera - it needs to follow an entity, but it doesn't own it - the entity manager does. The advantage of weak_ptr is that you can check whether the object it points to has already been destroyed.
Last edited on
Thank you for the reply. I decided to use the "standard" shared_ptr and weak_ptr, but I think it is just Visual C++'s adaptation because I haven't seen them in any standard references such as the one on this site. Is there a usage difference between this one and the one provided by Boost?

Regardless, I wrote a test program below to simulate the situation I described with the camera and entity system. It seems to do what it should. I check if the shared_pointer has not been deleted by using weak_ptr::expire().

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#include <iostream>
#include <list>

using namespace std;

//entity class
class CEntity
{
public:
    long id;
    long hp;
    CEntity() { id=-1; hp=0; }
};

//abbreviated CEntity shared pointer
typedef std::shared_ptr<CEntity> SP_CEntity;
typedef std::weak_ptr<CEntity> WP_CEntity;

//entity list
std::list<SP_CEntity> entityList;

//creates a new entity in a shared_ptr and adds it to entityList
void MakeEntity(long id)
{
    CEntity newEntity;
    newEntity.id = id;

    shared_ptr<CEntity> entityPtr(new CEntity);
    *entityPtr.get() = newEntity;

    entityList.push_back(entityPtr);
}

//returns a shared pointer to the entity with the id
SP_CEntity GetEntity(long id)
{
    std::list<SP_CEntity>::iterator iter = entityList.begin();
    
    while (iter != entityList.end())
    {
        if ( (*iter).get()->id == id )
            return *iter;

        iter++;
    }

    return NULL;
}

//deletes the entity from entityList and memory
void DeleteEntity(long id)
{
    std::list<SP_CEntity>::iterator iter = entityList.begin();

    while (iter != entityList.end())
    {
        if ( (*iter)->id == id )
        {
            (*iter).reset();
            entityList.erase(iter);
            break;
        }

        iter++;
    }
}


int main()
{
    //make some entites for testing
    MakeEntity(0);
    MakeEntity(1);

    //this is the pointer the camera has
    WP_CEntity target = GetEntity(0);

	//should entity 0 be deleted?
    bool d = false;
    cout << "Do you want to delete entity with id=0?  (1=yes,0=no)" << endl;
    int input=0;
    cin >> input;
    if (input == 1)
        d = true;

    //delete entity 0 if requested
    if (d)
        DeleteEntity(0);

    //see what's up with the target weak_ptr
    if (target.expired())
        cout << "Target entity non-existent!" << endl;
    else
    {
        cout << "The camera is accessing data from the target..." << endl;
        cout << "  id = " << target.lock()->id << endl;
    }
    
    return 0;
};
Last edited on
Topic archived. No new replies allowed.