When should TObjectPtr<T> be used outside of UPROPERTYs?

Is the recommended pattern to use TObjectPtr<T> only for UPROPERTY members within UCLASS and USTRUCT, and to use raw T* for function parameters and local variables? In other words, should TObjectPtr values generally be converted to raw pointers as soon as possible during usage?

Are there any edge cases where using TObjectPtr outside of properties (e.g., as function parameters or local variables) is expected or preferred?

The docu on https://dev.epicgames.com/documentation/en-us/unreal-engine/unreal-engine-5-migration-guide states:

Although it is optional, we recommend using TObjectPtr<T> over T* for UObject pointer properties and container classes found in UCLASS and USTRUCT types.

The code example shows both TObjectPtr and raw pointers used for function parameters with the TObjectPtr described as a rare exception to be used only if necessary.

Thanks for the answers, that confirms our approach as the correct one.

For example there are cases in the engine code where TObjectPtr is used locally, within a function, to store the result of creating an object with NewObject

Why is that done in those cases? Does it provide any benefits, such as for debugging?

Hi,

The short version:

The current rule of thumb is that you don’t need to use TObjectPtr outside of UPROPERTY members.

The longer version:

We have four current use cases for TObjectPtr:

  1. Access tracking during cook for computing dependencies for incremental cooks [experimental]
  2. Allowing for incremental garbage collection [experimental]
  3. Facilitating remote object references on other machines [pre-experimental]
  4. Allowing for lazy load of imported references [not currently used]

Each of these usage scenarios has slightly different needs, and these usage scenarios change over time. But we need consistent guidance for TObjectPtr usage that doesn’t change with the usage scenarios, and the simple rule of thumb above is adequate. There are a few situations where you might have a frequently running inner loop with some condition that receives TObjectPtr and converts them to raw pointers, and that will function correctly but cause every TObjectPtr to count as being accessed and trigger the access tracking logic even if the condition doesn’t pass and we don’t actually access it. That’s an example of a situation where it can be desirable to not convert from TObjectPtr to raw pointer. But these are abnormal and not something that should be part of general guidance.

A more complete rule would be: Use TObjectPtrs when you have object references that will be expected to span a garbage collect.

Hi Lukas,

It’s fine to use TObjectPtr for member variables that are not marked as UPROPERTY, however you may find that it would make more sense to be using TWeakObjectPtr in those cases (e.g. if you are storing a reference to a variable that is marked as UPROPERTY in a separate object, you don’t necessarily need to mark it as UPROPERTY again, but you might want to just use a weak pointer in that case instead).

In the engine, TObjectPtrs are mainly just used for member variables, and scarcely used for function parameters and local variables. I would recommend that you use raw pointers for your local variables and function parameters, however you don’t need to worry about converting your TObjectPtrs to raw pointers before using them. TObjectPtr overrides operator-> with Get(), which in turn calls ObjectPtr.Get(), which resolves the UObject, which returns a pointer. All of these functions are FORCEINLINE or inline, so the compiler should be able to collapse all of the calls to essentially just a single raw pointer access.

As for if there are any edge cases where it would be recommended to use TObjectPtrs outside of properties, there may be some obscure cases where this makes sense, but I wouldn’t worry about that until you come across it. For example there are cases in the engine code where TObjectPtr is used locally, within a function, to store the result of creating an object with NewObject, however this is not common, and most other similar usages of NewObject in the engine do not do this.

Hopefully this answers all of your questions.

Thanks,

Jasper

Hi Lukas,

It’s not clear to me that there are any benefits to using TObjectPtrs locally within a function. It’s hard to say without asking the person who wrote the code.

If you’re looking for a more definite answer on this, I can look at elevating this case to epic for a second opinion. Otherwise, let me know if you have any further questions.

Thanks,

Jasper

1 Like

I think it would help people to have a clear direction, in general for all readers on this topic.

If there is no benefit in using TObjectPtrs locally, neither now nor with there being any plans for additional support for this case in the future, then that would allow for a pretty clear policy.

I would very much appreciate getting advice from Epic on this. Thank you.