Re: Deleting Pointers from STL Vector

kanze_at_gabi-soft.fr
Date: 10/04/03


Date: 3 Oct 2003 21:51:30 -0400

Hanzo <hanzo@milclan.com> wrote in message
news:<omhnnv4l0nfkbdv7014dovil94s2ang3g1@4ax.com>...
> I'm iterating over a vector of base class pointers and deleting those
> which meet a certain criteria...i'm using pretty text-book code for
> the particular delete/erasure (it's straight out of Myers' Effective
> STL), and reads like this:

> void CGame::RemoveDeadObjects()
> {
> // cleanup crew!!
> vector<CDrawableObject*>::iterator i;
>
> for (i = g_vecGameObjects.begin(); i != g_vecGameObjects.end();)
> {
> // if object is not null and can be removed...
> if ((*i) && (*i)->CanRemove())
> {
> // grab hold before erasure
> CDrawableObject* toDie = *i;

> // erase...
> i = g_vecGameObjects.erase(i);

> // ...and kill
> delete toDie;
> toDie = NULL;
> }
> else
> ++i;
> }
> }

> Here's the problem: on the two lines that say delete toDie; toDie =
> NULL; I am noticing that the original variable to which toDie is
> pointing is not being set to NULL, just "toDie" itself.

Normal, no. You told the compiler to set toDie to NULL. You didn't tell
it to do anything else. In this case, setting toDie to NULL is for all
intents and purposes a no-op, and a any halfway good optimizing compiler
will eliminate the line completely.

I'm not sure what you mean by "the original variable". The variable
toDie contains a copy of the element which was in the vector. This
element has been erased. It doesn't exist any more, so it can't be set
to NULL.

There may, of course, be other variables designating the element. The
compiler has no way of knowing this, and it is your responsibility to
manage them. There are several alternatives, according to your needs:

  - If just setting them to null is sufficient, there are different
    types of smart pointers. If you use boost::shared_ptr in the array,
    any boost::weak_ptr pointing to the object will appear to be NULL;
    in many cases, this is a sufficient solution. If for some reason,
    using boost::shared_ptr is not an alternative (although frankly, I
    cannot think of one), I have a ManagedPtr at my site which will
    automatically become null when the pointed to object is destructed;
    it is considerably less flexible than the Boost solution, however,
    since it places significant constraints on the pointed to object.

  - If you are storing the pointers in other collections, say because
    another object might want to refer to several GameObjects, then you
    also need some way of removing the pointers from the collection
    entirely, to avoid memory leaks. The simplest way to do this is
    just to use weak_ptr, as above, and scan the collection periodically
    (say each time you modify it) to suppress any weak_ptr whose objects
    no longer exist. If the collections are really large, however, this
    may have unacceptable runtime overhead. In such cases, you need
    some means of informing the collection; this implies some sort of
    notification mechanism, in which the collection is a listener. My
    ManagedPtr uses a notification to inform the pointers to be set to
    null, and could easily be adopted to handle additional
    notifications. While this is definitely overkill when the first
    solution works, if you do need notification, the added complexity
    that ManagedPtr introduces will be necessary anyway.

  - More generally, it may be that the object holding a pointer to the
    deleted object needs to do more than just delete the relationship.
    In this case, you need to use the Observer pattern. The destructor
    of the object informs all classes which have expressed an interest
    in it that it is going to die, and they do whatever they have to do.

> In other words, if one of the CDrawableObjects* was say, a member var
> of CGame called m_cdPlayer1, when the delete/set-to-NULL happens:

> 1. Before the delete, toDie and m_cdPlayer1 have a value of
> 0x00a72498.

> 2. After the delete, both toDie and m_cdPlayer1 have their __vfptr
> point to memory 0xFEEEFEEE (signifying a delete)

I think you are speaking about something in the pointed to object
itself. If both pointers point to the same address, it is normal that
reading through either pointer will result in the same thing.

> 3. After the set-to-null, the value of toDie becomes 0x00000000, while
> m_cdPlayer1 remains at a value of 0x00a72498 (while still pointing to
> 0xFEEEFEEE).

What else should (or even could) happen. The compiler has no way of
knowing which objects might or might not have pointers to the same place
as toDie. Changing toDie changes toDie, and nothing else in the
program.

> Not the behavior I want. At this point, m_cdPlayer1 is officially
> deleted, yet the test "if (m_cdPlayer)" fails, since it is technically
> not NULL.

> Any suggestions or recommendations on how to get the intended behavior
> out of this snippet?

See above. The easiest solution to begin with is to use
boost::shared_ptr in the vector, and boost::weak_ptr every where else.
But sooner or later, you'll run into a case where you need full
notification; every professional I know of has some sort of change
notification mechanism in his toolbox.

--
James Kanze           GABI Software        mailto:kanze@gabi-soft.fr
Conseils en informatique orientée objet/     http://www.gabi-soft.fr
                    Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]


Relevant Pages

  • Re: Deleting Pointers from STL Vector
    ... > I'm iterating over a vector of base class pointers and deleting those ... indirection to give you the "desired" effect. ... of pointers and indirection. ... The variable toDie is a local variable, ...
    (comp.lang.cpp)
  • Re: Deleting Pointers from STL Vector
    ... toDie is set to 0x00000000 after the delete and assignment to NULL. ... walk a vector of base pointers, and delete/NULL them, affecting the ... Some people have also suggested smart pointers and boost, ...
    (comp.lang.cpp)
  • Re: Deleting Pointers from STL Vector
    ... This is fundamentally impossible using dumb pointers. ... No matter what you do to *m_cdPlayer1, including deletion via toDie ... The correct solution is to use smart pointers. ...
    (comp.lang.cpp)
  • Re: Deleting Pointers from STL Vector
    ... but modify only the poiter "toDie". ... You should store pointers to pointers instead like this: ...
    (comp.lang.cpp)
  • Re: new IL: C (sort of...).
    ... only for "recent" Pascals, ... far pointers weren't really limited, ... in my compiler, I made wchar_t a builtin type (in most cases, aliased to ... I could very well include builtin "managed strings" in the new IL. ...
    (comp.lang.misc)