When do we need to apply an empty UPROPERTY() to a class field?

In my current understanding, UPROPERTY() with specifiers (such as EditAnywhere, VisibleAnywhere, EditDefaultsOnly, BlueprintReadOnly, etc) is used to expose a class field to either Details panel of UE editor or Blueprint.

In my learning journey, I often find some EMPTY UPROPERTY() (without any specifiers) in UE code base as well as in many other tutorials.

The following example taken from APawn:

protected:
	/** Delegate broadcasted when possessing a new pawn or unpossessing one */
	FPawnChangedSignature OnNewPawn;

	/** The control rotation of the Controller. See GetControlRotation. */
	UPROPERTY()
	FRotator ControlRotation;

	UPROPERTY(EditDefaultsOnly, Category="Controller|Transform")
	uint8 bAttachToPawn:1;

	/** Whether this controller is a PlayerController. */
	uint8 bIsPlayerController:1;

	/** Whether the controller must have authority to be able to call possess on a Pawn */
	uint8 bCanPossessWithoutAuthority:1;

	/** Ignores movement input. Stacked state storage, Use accessor function IgnoreMoveInput() */
	uint8 IgnoreMoveInput;

	/** Ignores look input. Stacked state storage, use accessor function IgnoreLookInput(). */
	uint8 IgnoreLookInput;

As you can see, some fields are decorated with empty UPROPERTY().

QUESTION:
When do we need to apply an empty UPROPERTY() to a class field? I also often see an empty UFUNCTION() is applied to member functions. What are they for?

I heard (but not quite understand) that it is about reflection and garbage collection. Could you elaborate more on these parts as well because I am still confused in understanding how we decide whether a field needs an empty UPROPERTY() or a member function needs an empty UFUNCTION.

1 Like

You answered this in the next paragraph.


Each macro is to mark the variable/function for reflection. With UPROPERTY that also involves the garbage collector. If you don’t use the macro then the garbage collector doesn’t know you are referencing it.

UUserWidget* MyHUD;

If you have code like that inside your character class without the UPROPERTY macro, and if nothing else is pointing to it that does have the macro then from the GC’s perspective it’s free to clean up as “nothing” is using it.


You’ve seen examples of delegates using standard C++ using function pointers and vectors. That is not how Unreal implements them. Instead of function pointers Unreal stores function names, in order to be able to refer to functions by name the function needs to be reflected.

1 Like

But MyHUD does NOT have the macro UPROPERTY() so it will not be garbage collected if nothing is using it?

So the conclusion, do we have to always decorate every data member with at least an empty UPROPERTY() to take advantage of garbage collection?

Is it dangerous if we don’t use empty UPROPERTY for data members that we don’t want to expose to UE editor or blueprints? In my understanding, UE uses smart pointer, so garbage collection should not be mandatory because smart pointers can keep track of their own lifecycle.

1 Like

In both cases it will get garbage collected. The difference being that without it then the GC could free it while you’re still using it. In a nutshell using UPROPERTY adds to the reference count (though they aren’t reference counted IIRC but it’s easier to think of it like that).

The takeaway is that you should use empty UPROPERTYs on UObjects you don’t want to be freed from under you.

I used that specific example as more than one student has experienced their widgets from being deleted by the GC and thus their pointer pointing to invalid memory whilst they were still using it.

They have smart pointer types but UObjects themselves are managed via the GC.

2 Likes

Anyway it sounds weird if GC frees data members that are still in use if they are not decorated with at least an empty UPROPERTY().

1 Like

The GC uses reflection to know about these things. If you don’t use UPROPERTY then it’s not reflected.
I can enumerate all reflected members of a class by doing

void AProjectile::BeginPlay()
{
	Super::BeginPlay();

	UE_LOG(LogTemp, Warning, TEXT("AProjectile has the following properties:"))
	for (auto* Prop : TFieldRange<FProperty>(GetClass()))
	{
		UE_LOG(LogTemp, Warning, TEXT("\t%s"), *Prop->GetName())
	}
}

And that code wouldn’t print anything that doesn’t have UPROPERTY as those weren’t reflected.

2 Likes

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms