Member UPROPERTY vars reset to NULL after Actor Constructor call

Very simple but annoying problem:

In C++ in the constructor of an actor, I create some USceneComponents like this:

PlatformComponent  = ObjectInitializer.CreateDefaultSubobject<USceneComponent>(this, TEXT("PlatformComponent"));

PlatformComponent is a private var:

UPROPERTY()
		USceneComponent* PlatformComponent;

However, if I want to access this component in the PostInitProperties() method, PlatformComponent is a NULL pointer.

Why?
Also, creating a CapsuleComponent works fine and is available in PostInitProperties(). On top of that, the RootComponent, which is also a SceneComponent, is also available, but any other SceneComponent subobjects I create are getting invalid (but they still work since I see them in the editor and they are saved in the private var within the constructor scope)…

Hi,

This code is not clearly explain how you achieve mainComp. Make sure that mainComp is not NULL in that moment.
I checked next code and it should work.

PlatformComponent = ObjectInitializer.CreateDefaultSubobject<USceneComponent>(this, TEXT("PlatformComponent"));

Hope it helps!

That was a mistake but thanks. I figured out the source of the problem:

Defining the member variable without the UPROPERTY definition keeps the value valid. I made a trace to where the value is overwritten and it happens in UObjectGlobals.cpp at line 2131:

UObject* ClassDefaults = bCopyTransientsFromClassDefaults ? DefaultsClass->GetDefaultObject() : NULL;		
		for (UProperty* P = Class->PropertyLink; P; P = P->PropertyLinkNext)
		{
			if (bNeedInitialize)
			{		
				bNeedInitialize = InitNonNativeProperty(P, Obj);
			}

			if (bCopyTransientsFromClassDefaults && P->HasAnyPropertyFlags(CPF_Transient|CPF_DuplicateTransient|CPF_NonPIEDuplicateTransient))
			{
				// This is a duplicate. The value for all transient or non-duplicatable properties should be copied
				// from the source class's defaults.
				P->CopyCompleteValue_InContainer(Obj, ClassDefaults);
			}
			else if (P->IsInContainer(DefaultsClass))
			{
				**P->CopyCompleteValue_InContainer(Obj, DefaultData);**
			}

I have no idea why an initialized property is being reset by the Object Initializer? Why would it do that? Is this a bug or am I missing something?

Further trial & error showed that most likely, the problem is in the private var definition.

Making the vars public solved these var-reset problems. Still might be something to dig into from the engine dev side…

Nevermind, the problem reappeared even with public member vars when assigned the UPROPERTY macro…

I guess I could get the component outside of the constructor by iterating through the components and filtering by name, but why is it reset in the first place?

So as a workaround, I simply copy the pointer and save it as a native member var:

public:

	UPROPERTY(EditAnywhere)
		USceneComponent* PlatformComponent;

	USceneComponent* PlatformComponentPtr;

In the constructor:

PlatformComponent = ObjectInitializer.CreateDefaultSubobject<USceneComponent>(this, TEXT("PlatformComponent"));

	PlatformComponentPtr = PlatformComponent;

You actually have to attach it to the actor, otherwise it will just be garbage collected.

Either set it as root

Code:

PlatformComponent = ObjectInitializer.CreateDefaultSubobject<USceneComponent>(this, TEXT("PlatformComponent"));
RootComponent = PlatformComponent;

or attach it to the existing root (or any other component)

Code:

PlatformComponent = ObjectInitializer.CreateDefaultSubobject(this, TEXT("PlatformComponent"));
PlatformComponent->AttachParent = RootComponent;

The garbage collector only works on variables marked with UPROPERTY(), so removing it also disables garbage collection for this variable.

I’m not sure if it’s actually garbage collected since I can still use it and see it in the editor.

Also, is there a difference between using ->AttachParent and ->AttachTo(…) ?
Because I was using the latter to attach it to the RootComponent but it still wouldn’t work (resetting the pointer).

Answer here: UPROPERTY member vars reset to NULL by ObjectInitializer - C++ - Unreal Engine Forums

Answer here: UPROPERTY member vars reset to NULL by ObjectInitializer - C++ - Unreal Engine Forums

Short answer is:
UObject properties need to be Instanced. Double check your existing components to ensure the property was created correctly.

UPROPERTY(EditAnywhere, Instanced)
I’ve put the EditAnywhere so it’s easy to check if the property exists, and reset it if it was serialized in the level with a bad value, like NONE