May 12, 2014

Range-Based For Loops

By James Golding

In the Unreal Engine 4 code base, we have started taking advantage of some of the cool features added in C++11. We are cautious when adopting new language features because we target a wide range of platforms with varying compiler support. One of my favorite new features though is 'range-based for loops', which now works on Unreal's TArray, TMap and TSet containers. Here is an example of how this can really clean up common game code. Previously if I wanted to iterate over an array of AActor* pointers, it used to look like:

TArray<AActor*> Actors;
for (int32 ActorIndex=0; ActorIndex<Actors.Num(); ActorsIndex++)
{
	AActor* Actor = Actors[ActorIndex];
	Actor->SetActorLocation(NewLocation);
}

But using the 'range-based for loop' syntax it now looks like:

TArray<AActor*> Actors;
for (AActor* Actor : Actors)
{
	Actor->SetActorLocation(NewLocation);
}

How nice is that! Here is another example with a TMap – it used to look like this:

TMap<AActor*, FMyStruct> ActorStructs;
for (auto ActorStructIt = ActorStructs.CreateIterator(); ActorStructIt; ++ActorStructIt)
{
	AActor* Actor = ActorStructIt.Key();
	FMyStruct& Data = ActorStructIt.Value();
}

But now it looks like:

TMap<AActor*, FMyStruct> ActorStructs;
for (const auto& Entry : ActorStructs)
{
	AActor* Actor = Entry.Key;
	const FMyStruct& Data = Entry.Value;
}

Note that you are still responsible for putting 'const' or '&' on the variable you declare e.g.

TArray<FVector> Positions;
for (FVector& Position : Positions)
{
	Position.z += 10.f;
}

You need to add the ‘&’ to have a reference to rather than a copy of the FVector. We are not going to start reformatting every for loop in the engine, but I certainly plan to use this syntax a lot going forward.

I’d love to hear what you guys think about this feature and answer any questions you might have. Be sure to find me over on Twitter at @EpicJamesG or in the forums!