Will a UPROPERTY within a non-UPROPERTY member work?

My question is probably best explained with very little code:

USTRUCT()
stuct FMyGCWrapper
{
    GENERATED_USTRUCT_BODY()

public:
    UPROPERTY()
    UObject* StoredObject;
};

The above struct only has 1 purpose: to store the referenced object that would otherwise not be a UPROPERTY into a UPROPERTY (I would also implement a constructor that takes a UObject* and override the operator== for use below, but lets skip this for the example).

UCLASS()
class USomeClass : public UObject
{
    GENERATED_BODY()

private:
    // Static UPROPERTY isn't supported.
    // Will the UPROPERTY in FMyGCWrapper properly be recognized or not since
    // the referencing variable isn't marked as UPROPERTY?
    static TArray<FMyGCWrapper> s_References;
public:
    virtual void BeginPlay() override { s_References.Add(FMyGCWrapper(this)); }
    virtual void BeginDestroy() override { s_References.Remove(FMyGCWrapper(this)); }
};

Now my question: will this prevent garbage collection of all objects stored in s_References if they are not hard referenced anywhere else? If not, is there a way to store hard references to UObjects in non UPROPERTY fields? There is no TObjectPtr or something like that, only weak pointers (talking about TWeakObjectPtr).

I would also like to get answer to this question.

No this won’t prevent garbage collection nor provide auto-nulling capability.

If you want to keep an object alive without UPROPERTY, manage it into the root set manually by calling Object->AddToRoot and Object->RemoveFromRoot.

Keep in mind that if a rooted object references World/Actors (directly on indirectly), it may prevent garbage collection and cause crash when changing levels.

But why exactly this won’t prevent garbage collection?
Is it because s_References member is static? Is it because it’s struct? Or is it because it’s not marked with UPROPERTY?
Is UPROPERTY chain required for proper garbage collection, meaning that every ancestor of member needs to be also marked with UPROPERTY?

The chain is required in usual usage scenarios, although there’s also the possibility of overriding AddReferencedObjects and adding objects manually there.

If you use AddReferencedObjects in USomeClass to keep objects in your static variable alive, it’ll only work as long as your USomeClass is alive (at least one instance of it), which kind of defeats the purpose of having it static in the first place (use a singleton instead).

1 Like