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