Tuesday, 8 April 2025

UE5: TArray<>.Reserve(N) vs .SetNumUninitialized(N)

TArray<>.Reserve(N)

A safe way to pre-allocate memory capacity for an array to avoid reallocations during dynamic growth.

+ rather safe
+ pre-allocating prevents runtime heap-allocations
- faster than runtime allocation, but slower than ".SetNumUninitialized()"

Correct example:

TArray<FVector> MyVectors;
MyVectors.Reserve(32);
const int32 LoopLength {18};

for (int32 i = 0; i < LoopLength; i++)
MyVectors.Add(FVector(42.0, 42.0, 42.0));

"LoopLength" can be anything between 0 and 32 in this case. If the loop exceeds the reserved capacity (32 in this case), subsequent ".Add()" calls will still work but will trigger memory reallocations, reducing the performance benefit gained from the initial reservation. So try to enter a correct number if possible.

TArray<>.SetNumUninitialized(N)

A not so safe, but very performant way to reserve memory with manual initialization.

+ fast (removes ".Add()" overhead)
+ pre-allocating prevents runtime heap-allocations
- unsafe if not all elements are correctly initialized (direct access using [index])

Correct example:

TArray<FVector> MyVectors;
MyVectors.SetNumUninitialized(32);
const int32 LoopLength {32};

for (int32 i = 0; i < LoopLength; i++)
MyVectors[i] = (FVector(42.0, 42.0, 42.0));

Crucially, you must ensure your code explicitly initializes every element index "i" (from 0 up to N-1) that you intend to read from later. If your code attempts to access an index "i" where "i" >= N (the size set by SetNumUninitialized), it will result in an out-of-bounds access, likely causing a crash. As a best practice: simply match "SetNumUninitialized()" with "LoopLength" to prevent any issues.

No comments:

Post a Comment