For each loop on TArray

Hi everyone,
This one seems to be trivial but I do not know how it should be done. Basically I want to create an array of actors and operate on it. I can create an array and add actors to it but I cannot understand how to include the array in a foreach loop.

Can someone provide a basic example of it

for (int i = 0; i < Array.Num(); i++) {
Actor = Array[i];
}

I think you’re looking for “.Num()”

2 Likes

Exactly what I was looking for, thank you

You can also use nicer ranged-for syntax:

for (AActor* Actor : Array)
{
    Actor->SomeActorFunc();
}

Steve

12 Likes

Yes, this one I love and marry.

I know this was a long time ago now, but does this
for(AActor* Actor : Array)
{

}
Return an index in its scope?

sadly no. That syntax works as an iterator.

that’s how it is done in 2017. (actually since 2011)

for (auto &x : array){
    x.   
}

I seriously doubt there’s any measurable difference in performance between the two versions. More likely they compile to the same exact machine code. Give the compiler some credit.

Well, it is not for-each, it is for. Still, there are three problems:

  1. It is bad idea to use Array.Num() inside of for statement.
  2. There is no sense in using i++ instead of ++i.
  3. You don’t usually need int as it is too huge for not-BigData (and can differ in size from one C++ standard to another).

In terms of performance, it is better to write in other way, so that your code won’t run in too different time on different compilers:

/* If you do care about order... */
uint8 Len = Array.Num();
for (uint8 i = 0; i < Len; ++i)
{
    Array[i].DoStuff();
}

/* And if you don't... */
for (int8 i = Array.Num() - 1; i >= 0; --i)
{
    Array[i].DoStuff();
}

Update: one more variation…

for (uint8 i = Array.Num() - 1; i-- ; )
{
    Array[i].DoStuff();    // However, it won't reach 0-th element...
    // Array[i - 1] can work if we start from Array.Num() element, but it's +1 operation on each iteration...
}

I agree that some compilers do this work for us, but some not. One either test it, or manually write an appropriate version for the certain situation.

General.
Off-top: for Intel C++ compiler O2, O3 might be useful.

WHSolv, I disagree on all three points:

  1. It’s not necessarily a bad idea to use Array.Num() inside the loop signature. As RotemS pointed out, if the length of the array doesn’t change based on the code inside the loop body then the compiler will VERY likely optimize the call to Num() out of existence. I agree that relying on compilers too much for optimization is not a good thing, but to simply state that it should never be done without qualifying that in any way isn’t something I can agree to.

  2. For the same reason as #1 and because there is no additional logic to occur anyway (in this example), there is actually no sense in using ++i over i++ (or vice-versa). I don’t even see a semantic difference in using either since it should be clear to the reader that nothing is going to happen to i either before or after it is assigned.

  3. Are you targeting 8-bit processors or extremely memory deprived systems? Why use int8? More than likely, if you are using UE4, you are targeting 32-bit or 64-bit processors, which have 32/64-bit registers. Unless the compiler saves you, using smaller sized types may actually result in poorer performance (though you’ll save on memory, but for cases like indexers for loops don’t bother with int8 or using an unsigned integer just because logically it shouldn’t go negative).

If in the loop body you plan on using the variable “i” to access a specific element in the array and the length of the array won’t change inside the loop body, then performance-wise the best approach is to use a for each loop like Steve suggested.

Cheers

Just wondering what Reserve() is responsible for. I’ve never seen such a thing.

I’m not going to comment on the “optimal” way to iterate through TArrays, but the following is how they are iterated in the engine code, so I assume this method is at least safe.

TArray<ExampleClass> MyArray;

// Some code which assigns value to the array...

// Iterate through the array
MyArray.Reserve(MyArray.Num());
for (int i = 0; i < MyArray.Num(); ++i)
{
   // Extract item from the array
    ExampleClass MyItem = MyArray[i];
}

Source: UE 4.20.1 - Engine/Source/Runtime/Engine/Private/Actor.cpp Line 2699

@WHSolv - In the engine code, TArrays are iterated by using Num (with a reserve), ++i and int type.

According to the documentation, it “reserves memory such that the array can contain at least Number elements.”

Source

Thanks! Didn’t touch UE for weeks – forgot there is a documentation on-line.

++i increases the index prior to the loop body executes and i++ increases the index after the loop body executes.

++i increases the index prior to the loop body executes and i++ increases the index after the loop body executes.

The above is untrue - please check the manual: for loop - cppreference.com

“…which is executed after every iteration of the loop and before re-evaluating condition. Typically, this is the expression that increments the loop counter”

for : is the for each statement in C++. Just because theres no foreach keyword doesnt mean it isnt the same thing.

  1. No, its not. If the array isnt being mutated then its fine, and if it is, then i cache the array first.

  2. Its literally a stylstics choice. No one in the history of ever has had worse preforming code because they put the plus signs in the wrong order. Its a complete over reaction, and any code compiler could refactor i++ into ++i if it can. This is micro optimizing.

I prefer i++ because it makes more semantic sense to me. Theres i = i + 1, i += , i.Add(1) so naturally i++ is more constistent to have the identifier first, then the operation afterwards. Preformance wise it will almost never make a difference, and if it does, then that’s the fault of the implimenter of the ++ operator.

  1. What? Are you in the 70s? Computers can handle using even 1000s of ints that arent needed, this is abusrd. In C#, for example, an int is actually faster than a byte or short, because the compilers were designed more efficently to use ints, because they were more common, so it might actually be better to use int.

Do you have any measurements for any of this? This is such a micro optimization that literally doesn’t matter. You’re talking about the preformance of a for loop