Question regarding Transient and Pointers

Before we kick off, I wanted to mention, that I’m fairly new to programming in Unreal. Right now I’m just looking at source code to get an understanding of how things are meant to be done.

Let me give you two excerpts from ACharacter and ACharacterMovementComponent, before asking my question.

In the ACharacterMovementComponent class there is a pointer to the owerning ACharacter.
Lets call the following line Example 1:

UPROPERTY(Transient, DuplicateTransient)
TObjectPtr<ACharacter> CharacterOwner;

So far so good.

This pointer is not set in the constructor, but rather through these two methods of the ACharacterMovementComponent class:

ENGINE_API virtual void SetUpdatedComponent(USceneComponent* NewUpdatedComponent) override;

and

ENGINE_API virtual void PostLoad() override;

On the other hand, there are many pointers to components in the ACharacter class.
I’m just going to pick one and call the following line Example 2:

UPROPERTY(Category=Character, VisibleAnywhere, BlueprintReadOnly, meta=(AllowPrivateAccess = "true"))
TObjectPtr<UCapsuleComponent> CapsuleComponent;

This pointer is set directly in the constructor via

CreateDefaultSubobject<UCapsuleComponent>(ACharacter::CapsuleComponentName)

As far as I know, for every UCLASS the constructor is called exactly once, when creating the corresponding CDO (Class Default Object), which then serves as a template for every instance created further down the line.

  • Question 1

So for my first question, wouldn’t Example 2 imply, that all character instances share a pointer to the same capsule component instance, since the pointer is set in the constructor, which is only being used once when creating the CDO as a template?

  • Question 2

And for my second question, why would Example 1 be marked as Transient, while Example 2 would not.

The way I understand Transient as a property specifier, it prevents saving to and loading from disk. So why would it be a good idea to prevent Example 1 from being saved and loaded, but not Example 2, since both are just pointers. Saving and loading pointers instead of actual objects sounds like a bad idea to begin with.

If someone can recomend a good read on the matter, I will gladly get the answers myself. After days it feels like the more I look, the less I find on the matter.

This is a bit complicated and I fully understand why you’re confused by it. Good you’re digging into the sorce code, but you may wanna read the overview about Unreal’s C++ programming first, especially section about Reflection and UObjects. Have in mind that Unreal does not use vanilla C++, instead it parses the .h files via UnrealHeaderTool and generates intermediate code. Because of it a lot of things works differently than you would expect, especially when comparing to regular C++

Now, let’s answer your questions:

  1. No, each ACharacter instance has it’s own UCapsuleComponent. CDO behaves like a template for creating instances - it only stores default values and Factory uses those for spawning new instances. CDOs and Factories are used like this because of the Reflection system, garbage collection and hot code reloading (and more). Setting default values inside of constructor is also a good practice that decreases compilation times, since any changes inside of .h file force you to recompile all corresponding .cpp files.
  2. Yes, Transient means that variable is not being serialized - not saved when saving the Game, not saved as part of the Level when saving it in the Editor, not saved as part of Blueprint, etc. The reason why they are NOT setting it inside of constructor is that it’s just simply impossible in this case. You can only create a Subobject inside of constructor and Component’s Owner (CharacterOwner) is not a Subobject, you won’t be able to grab it in there, it simply isn’t known at the time, you must grab it at runtime. I’m not fully sure why they marked it as Transient though. Perhaps, just for safety reasons, since the initialization for this variable is always expected to be re-run, or maybe due to DuplicateTransient flag.

I hope those answers are enough :slight_smile:

2 Likes

Thanks a lot for that detailed explanation.

1 Like

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