Structs, USTRUCTS(), They're Awesome
Guide on using USTRUCTS by Rama the legend
Overview
Original Author: Rama
Structs enable you to create custom variable types to organize your data, by relating other c++ or UE4 C++ data types to each other.
The power of structs is extreme organization, as well as ability to have functions for internal data type operations!
Technical
Structs enable you to create custom variable types to organize your data, by relating other C++ or UE4 C++ data types to each other. The power of structs is extreme organization as well as the ability to have functions for internal data type operations. '
In UE4, structs should be used for simple data type combining and data management purposes. For complex interactions with the game world, you should make a UObject
or AActor
subclass instead.
Core Syntax
Additional Note Author: DesertEagle_PWN The idea of USTRUCTS() is to declare engine data types that are in global scope and can be accessed by other classes/structs/blueprints. Because of this, it is invalid UE4 syntax to declare a struct inside of a class or other struct if using the USTRUCT() macro. Regular structs can still be utilized inside your classes and other structs; however these cannot be replicated natively and will not be available for UE4 reflective debugging or other engine systems such as Blueprints.
Additional Note Author: Darkgaze Concerning the variables visibility on the editor: In the example above, if you don't add "EditAnywhere" parameter into UPROPERTY inside the members of the USTRUCT, whey won't show up in the Editor panel. You will see the variable but there will be no way to see/change/unfold the values inside. The class that defines a new UPROPERTY using that struct type should have that parameter too. In case you can't modify the data and you are using blueprints, you should add BlueprintType inside the USTRUCT parenthesis.
Examples
Example 1
You want to relate a float brightness value with a world space location FVector, both of which are interpolated using an Alpha value.
And you want to do this for 100 different game locations simultaneously. And you want to do this process repeatedly over time! You need to store the incremental interpolation values between game events. AActors/UObjects are not involved (You could just subclass AActor
/UObject
and store the data per instance)
Example 2
You want to track information about particle system components that you have spawned into the world through
and you want to track the lifetime of the particle and apply parameter changes from C++. You could write your own class, but if your needs are simple or you do not have project-permissions to make a subclass of UParticleSystemComponent
, you can just make a USTRUCT
to relate the various data types!
Particle Data Tracker
Now you can have an array of these USTRUCTS
for each particle that you spawn!
Garbage Collection
By marking a USTRUCT
or USTRUCT
array as UPROPERTY()
and marking any UObject / AActor members as UPROPERTY()
, you are protected from dangling pointer crashes
However you must also clear ustructs you no longer need if they have pointers to UObjects
if you ever want GC to be able garbage collect those UObjects
.
Structs With Struct Member Variables
The struct that wants to use another struct must be defined below the struct it wants to include.
Struct Assignment
My personal favorite thing about structs is that unlike UObject
or AActor
classes, which must be utilized via pointers (AActor*
) you can directly copy the entire contents of a USTRUCT
to another USTRUCT
of the same type with a single line of assignment!
Deep Copy
If you have struct members pointing to UObjects or array pointers, you must be careful to copy these members yourself!
On screen the output will be
instead of the expected
This is because the data stored in MyStruct::MyIntArray
is not actually stored inside of MyStruct
. The new keyword creates the data somewhere in RAM and we simply store a pointer there. The address the pointer stores is copied over to MySecondStruct
, but it still points to the same data. In fact, it would be counterproductive to remove this functionality since there are cases where you want exactly that. Additionally the Unreal Property System does not support non-UObject pointers, which is why MyIntArray
is not marked with UPROPERTY()
.
However, copying arrays of integers (e.g. int32[10]
instead of int32*
) means the data is stored directly inside the struct and as such "deep copied". However, if you store a pointer to a UObject
, this object is NOT deep copied! Once again only the pointer is copied and the original UObject
left unchanged. Which is good because otherwise you might manipulate the wrong instance thinking you only had one to begin with leaving the original UObject
unaffected, thus resembling a very nerve-wrecking and very difficult to track down bug!
Automatic Make/Break in BP
Marking the USTRUCT
as BlueprintType
and adding EditAnywhere, BlueprintReadWrite, Category = "Your Category"
to USTRUCT
properties causes UE4 to automatically create Make and Break Blueprint functions, allowing to construct or extract data from the custom USTRUCT
.
Special thanks to Community member Iniside for pointing this out. :)
Replication
Remember that only UPROPERTY(
) variables of USTRUCTS()
are considered for replication!
So if your USTRUCT
is not replicating properly, the first thing you should check is that every member is at least UPROPERTY()
! The struct does not have be a BlueprintType
, it just needs UPROPERTY()
above all properties that you want replicated.
Other notes
In case you are looking for GENERATED_USTRUCT_BODY
, in 4.11+, GENERATED_BODY()
should be used instead.
Related Links
UStruct data member memory management
Thank You Epic for USTRUCTS()
I love USTRUCTS()
, thank you Epic!
Authors
Original author: Rama <3 Captured from the epic wiki via the Wayback Machine. Reformatted by Maldonacho
Last updated