Array has changed during ranged-for iteration

I upgraded to 4.11 and now I have the following error:

Array has changed during ranged-for
iteration

This happens because I add some elements in my TArray while iterating over it. I am aware of what I am doing, the elements I add in the array should be processed in the same for loop.

TArray<FEdge*> Edges;
// [...] Fill Edges
for(FEdge* Edge:Edges)
{
   Process(Edge);
   if(Condition(Edge))
   {
       Edges.Add(new FEdge());    // Add a new edge to be processed later
   }
}

What is the prefered method of doing so? Using a while loop?

Using a index based for loop fixes the problem, but I’m am not sure it’s the best solution.

for (int32 i = 0 ; i < Edges.Num() ; i++)
{
    FEdge* Edge = Edges[i];
}
1 Like

Hi Arthur,

Modifying a container while iterating over it with a ranged-for has always been undefined behaviour, but happened to work with TArray. A change was made to optimise TArray’s ranged-for iteration which now prevents that case, so the assert was added to catch when you do that.

Using an index-based loop will be fine in your case.

Steve

1 Like

What is the difference between using a ranged-for and an index? I don’t understand how it can differ, unless TArrays do not use contiguous storage locations for their elements?

TArray is contiguous. But ranged-for uses iterators, not indices. Invalidating the begin or end iterator (which adding to a container does) while iterating is undefined behaviour.

Further reading: http://stackoverflow.com/questions/17076672/add-elements-to-a-vector-during-range-based-loop-c11

(std::vector here, but the situation is still identical)

Steve

Ok, I missed the disctinction between for(auto _begin = r.begin(); _begin != r.end(); ++begin) and for(auto _begin = r.begin(), _end = r.end(); _begin != _end; ++_begin) (the cacheing of r.end()) .