What is the best practice for Garbage Collection (UPROPERTY with/without TObjectPtr)

A general question about best practices and garbage collection.

When working with C++ with Rider and adding to a class an object pointer it will give the next warning:
Object member 'CapsuleComp' can be destroyed during garbage collection, resulting in a stale pointer

So to fix that I have two options:

  1. Add a UPROPERTY macro, expose it to Blueprints and to the UE Garbage Collection.
  2. Wrap the type with an TObjectPtr<T> which also marks it for UE’s Garbage Collection (as the documentation states “When resolved, its participation in garbage collection is identical to a raw pointer to a UObject”.

But what I’ve noticed is that the UE API uses both, UPROPERTY marco and TObjectPtr, for example the UShapeComponent class has:

UPROPERTY(transient, duplicatetransient)
TObjectPtr<class UBodySetup> ShapeBodySetup;

I’m wondering what is the best practice here?
When should I just use UPROPERTY macro and when should I use both? Or only TObjectPtr<T>?

You should use both, if you want to make sure that the reference is tracked and the object is not garbage collected

Without UPROPERTY, the reference won’t be tracked which means that the object will probably be garbage collected in the next cycle

TObjectPtr is basically just a raw pointer, with some extra functionality in editor builds. As far as I know, those will basically be used exactly as raw pointers in builds. And raw pointers are not tracked, so they can be garbage collected.

In certain rare cases, when you know that an object is for sure kept alive someplace else, you can skip the UPROPERTY, but that’s basically asking for trouble (although it is used in a couple places in the engine)

1 Like