I'm using a for loop or foreach loop (doesn't matter) to loop through all my objects when they need to be updated or drawn. However, when an object gets killed, I want it to get removed from the collection again.

I do this by adding the object to a dead-objects list, and then, when everything has been drawn and updated, I go through everything in this list, removing the objects in the list from the original source as well.

Is there a better way of doing this?

  • \$\begingroup\$ Relevant: Twin paths to garbage collector nirvana \$\endgroup\$ Oct 28 '11 at 0:12
  • 2
    \$\begingroup\$ This really has nothing to do with garbage collection, despite the use of the word "garbage" in the title and the answers so far that have mentioned the .NET Garbage Collector. \$\endgroup\$ Oct 28 '11 at 2:46
  • \$\begingroup\$ I took liberty to actually change the word "garbage" to "dead", to prevent confusion with .NET garbage collector. \$\endgroup\$
    – Nevermind
    Oct 28 '11 at 4:39
  • \$\begingroup\$ Oh I'm aware of that. The garbage collection article is still relevant because it may play into what you do with those dead objects. E.g. dead debris? Unlink it from everything, reset it to defaults, place back in the debris bucket. \$\endgroup\$ Oct 28 '11 at 5:47

First of all: terminology. If you say "garbage list", people will think you are talking about the garbage collector. Let's call it the "dead list".

As you have probably discovered, hence your question, you cannot remove items from a collection while you are iterating through it. If your collection is a List<> then the simplest way to remove items from it is:

for(int i = list.Count-1; i >= 0; --i)

Note that you iterate backwards. You can remove items while iterating forward, but it's messier and requires a goto. You cannot do it with foreach.

You can either do the removal separately from your update loop. Or you can merge it into your update loop. Always do the RemoveAt at the end of the loop - after that point in the loop, list[i] cannot be considered valid (it becomes valid again on the next iteration).

Note, also, that each object has its own IsDead flag (if you are using the disposal pattern, you could make it IsDisposed) - you don't actually need to maintain a "dead list" at all.

Using a flag on each item is preferable for performance, as you avoid having to search through the list to do removal. And it is also preferable for design - it means that each object can easily check if it is dead - so you don't accidentally call any methods on it (if these objects are implementing the disposable pattern, they could throw ObjectDisposedException in this case).

If you have a collection other than a List<>, then removing dead items from that collection may still involve the creation of a dead list (as removal during iteration may not be possible). In my opinion, it is nicer, design-wise, to create the dead list right before it gets used, by iterating over the collection looking for IsDead flags, rather than trying to maintain the list as objects are killed.

Once you are finished with a dead list, you should Clear() it, and then keep it around to re-use it later on.

  • \$\begingroup\$ So the disposable pattern is considered more 'effective' then? \$\endgroup\$ Oct 28 '11 at 6:29
  • \$\begingroup\$ @Jonathan: I don't understand your question. The IsDead pattern is functionally identical to IsDisposed. Semantically using IsDead implies that you're maintaining a Draw/Update list of these objects that will have dead items removed from it at a later time. The disposal pattern does not imply that. Moreover, the disposal pattern does imply that you may have unmanaged resources held by that object (which is usually not appropriate for gameplay objects). \$\endgroup\$ Oct 29 '11 at 6:04
  • \$\begingroup\$ You can do it with foreach with using reverse. \$\endgroup\$
    – shinzou
    Dec 8 '16 at 19:53

99.9% of the time, the garbage collector (GC) will take care of everything without hassles. Just let it do its work once you've deleted/nulled those objects. There is a latency in cleanup that depends on a number of factors (how many blocks of memory have been assigned for instance) but you don't need to typically even know about that, let alone worry about it. It's designed to just work. Which is one reason you're using C# and not C.

Re GC performance in general, don't concern yourself overly unless you happen to know (through profiling) that it is creating a bottleneck -- this is only in quite demanding games, generally. If this is the case, look into GC.Collect(), and its various pitfalls, so you know when it is appropriate to use it. I suggest googling "force gc xna", there is plenty of material out there.

  • \$\begingroup\$ So if I have a list that I am using in my Update() call every time, all elements in it where the element is "null" will automatically be cleaned up, AND removed? \$\endgroup\$ Oct 28 '11 at 0:17
  • \$\begingroup\$ @Mathias No. See my comment on your question. The garbage collector will not modify anything that you can still access - including your collection and its contents. \$\endgroup\$ Oct 28 '11 at 3:15
  • 1
    \$\begingroup\$ The question doesn't have anything to do with GC, except unfortunate choice of word "garbage". \$\endgroup\$
    – Nevermind
    Oct 28 '11 at 4:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.