Foreach Access Violation
Steven Schveighoffer
schveiguy at yahoo.com
Mon Oct 20 09:42:22 PDT 2008
"nobody" wrote
> Say I have a class Apple:
>
> class Apple
> {
> ..
> }
>
> Several apples are created:
>
> Apple[] apples;
>
> for(int i = 0; i < 10; i++)
> {
> apples.length = apples.length + 1;
> apples[apples.length-1] = new Apple();
> }
>
> Then I iterate over all the apples with a foreach loop
>
> foreach(int i, Apple apple; apples)
> {
> apples.iterate();
> }
>
> And in the iterate() some or more apples delete themselves via
>
> void die()
> {
> for (int i = 0; i < apples.length; i++)
> {
> if (apples[i] is this)
> {
> apples[i] = apples[$-1];
> apples.length = apples.length - 1;
> delete this;
> }
> }
> }
>
>
> This generally works fine, except when the last apple is deleted.
> Then I get an Access Violation Error in the foreach loop.
> When I use a for loop instead it works perfectly.
You are doing several things in the die function that are very bad.
#1, you shouldn't ever use delete this.
#1a, you should probably avoid using delete altogether. That is what the
garbage collector is for.
#2, if you insist on using delete this, you should exit the function
immediately afterwards.
#3, you are technically not allowed to change the length of the array during
foreach, although I don't see why that would cause an access violation.
#4, you should set apples[$-1] to null, to avoid dangling references to
memory so the GC will clean it up, especially if you follow suggestion #1a
>
> Is this because the foreach loop doesn't reevalute the length of the
> apples array
> while looping, or am I missing something else entirely?
My gut tells me that it's something else. Even if the loop is not
reevaluating length, the memory that it was pointing to is still valid
memory, so it shouldn't cause an access violation. The clue that it's the
last apple (BTW, does 'last' mean that there's only 1 element left in the
array, or many elements and you are removing the end element?) says that
probably it's the delete that's messing up something. Try printing out
information inside the foreach loop to see where the problem lies.
But unfortunately, in order to not violate the D spec, you should use a for
loop, not a foreach loop. That is the answer that you probably should
follow.
-Steve
More information about the Digitalmars-d-learn
mailing list