UPROPERTY member vars reset to NULL by ObjectInitializer

Hello devs,

does anybody have the same problem, UPROPERTY vars of an actor being reset to NULL after the constructor finishes?

Check out more details here:

I need the UPROPERTY because I want the components to be editable in the editor… is there a switch in the UPROPERTY macro that prevents the var from being reset? Or is this a bug?

2 Likes

I take it from the context of that AnswerHub question that this object of yours is blueprinted? It seems as though the CDO for that blueprint was saved with a null component. Thus, after running the constructor, the defaults are copied over to your object and the component is nullified. You should be able to tell if this is the case by getting the object instance somewhere in your code and looking at it with the debugger.

Components should be VisibleAnywhere, VisibleInstanceOnly or VisibleDefaultsOnly, never editable. Components being pointers, an editable component means you can edit the pointer to the component itself rather than the contents of the component, for instance allowing the component to be nullified. Which might be what somehow happened here along the way.

If this theory is correct, in order to get rid of the nullified component, you’ll have to get rid of the current blueprint CDO. Unfortunately where this CDO exists is something I’m not clear on. I think part of it is in the blueprint asset itself, and some derived data is also processed in the Derived Data Cache. Last time I’ve had issues with undesirable defaults saved to a blueprint CDO, I managed to clear it up by deleting the blueprint, deleting the DDC folders (Engine/DerivedDataCache + MyGame/DerivedDataCache) and then recreating.

4 Likes

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

Either set it as root


RootComponent = PlatformComponent;

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


PlatformComponent->AttachParent = RootComponent;

*edit: also posted on answerhub

No.

Garbage collection does not occur that early, for starters.

If all components needed to be attached in order to not be garbage collected, then non-scene components would all get garbage collected, since they cannot be attached.

There already is a managed reference to the component which should prevent it from being collected:


UPROPERTY()
USceneComponent* PlatformComponent;

Lastly, if it were a case of garbage collection somehow destroying the component, then it wouldn’t get nullified. The pointer would keep its value but point to a now dead object, with likely disastrous results.

You’re right in that the scene component needs to be attached somewhere in the scene in order to be displayed properly, but this is not what’s causing this issue.

1 Like

Thanks, this seems to be what is happening! I’ll try your suggestions with re-creating the blueprint.

But then I have a different question: How do I make the contents of the component editable? Or is this achieved by simply having the component as a public property?

With regards to public vs. private properties, I’m not 100% positive on this as the behaviour was changed in UE4.6 and we’re still on 4.5. 4.5 didn’t care about member visibility, but 4.6 seems to enforce it to an extent. From what I’ve seen discussed on the forums, I think it works like this:

Recommended practice is now to make components private and provide a getter function should they be accessed from outside the class. Like making component properties non-editable, this is to prevent components from being overwritten by “outside code”. This used to be protected through the TSubobjectPtr template, but this has been deprecated.

As mentioned earlier, making the component Visible seems to be all it takes for the component’s properties to be editable. I think this needs to specifically be VisibleAnywhere for the editor to handle the inline component property display.

All of this seems corroborated by the code in 4.6. Take a look at AStaticMeshActor for instance:



private_subobject:
	DEPRECATED_FORGAME(4.6, "StaticMeshComponent should not be accessed directly, please use GetStaticMeshComponent() function instead. StaticMeshComponent will soon be private and your code will not compile.")
	UPROPERTY(Category = StaticMeshActor, **VisibleAnywhere**, BlueprintReadOnly, meta = (ExposeFunctionCategories = "Mesh,Rendering,Physics,Components|StaticMesh", AllowPrivateAccess = "true"))
	class UStaticMeshComponent* StaticMeshComponent;

(...)

public:
	/** Returns StaticMeshComponent subobject **/
	class UStaticMeshComponent* GetStaticMeshComponent() const;


I’m guessing private_subobject is a macro that currently is public but will change to private once this deprecation is applied.

So, short version, try private and VisibleAnywhere.

I haven’t tested, but my suspicion is that it’s not related to the public/private declaration. So long as the component is visible, then the ability to edit its contents (ie. its own properties) is determined by the specifiers that were set on the properties within the component class itself.

Maybe it’s more complicated than I imagine, I am very new to UE4. From the way I understood things though, the CDO of a blueprint class is simply defined by the values set in the defaults section of that blueprint (and up the chain of its parent classes). A CDO is just an object with property values unchanged from the defaults defined by its class, right? In which case, if you’re right in your suspicion of the issue, then the following should work:

  1. Temporarily make the component property EditAnywhere.
  2. Reload the editor and open the blueprint in question.
  3. In its defaults, find the component. It would be set to None.
  4. Click the yellow arrow to reset it to the default from its parent class CDO, which should be the value set in the C++ constructor.
  5. Save and exit. Change EditAnywhere back to VisibleAnywhere.
6 Likes

Thanks guys, you were correct. I simply had to define it as VisibleAnywhere and prior to that reset it to the default (it was None!) in the defaults tab of the Blueprint! Also, having the components as private vars still shows the contents in the editor just fine.

4.7.3 - still there

We are also experiencing this on 4.7.3.
What our arrangement boils down to is really simple (pseudocode-ish for brevity).

I asked cmartel for help in PM and later decided to move the conversation here.

Thank you for pointing that out, I didn’t know that. But we are not overriding the component.
Our issue is exactly like described here or here. We haven’t had our project upgraded from 4.3.1 in a loong time, and this issue started appearing only when we introduced StatComponent (on the same engine version).
Our Character-derived assets seem to have been corrupted with null references and most of them (or all) had an empty StatsComponent tab in the editor. Any code access to StatsComponent outside of constructor code resulted in an obvious crash. I tried to fix this by doing what chaosgrind describes (setting Component uproperty to EditAnywhere, BlueprintReadWrite, then resetting assets to their default, then modifying back to VisibleAnywhere, BlueprintReadOnly) to find out that I couldn’t reset the component variable from None - there were no alternative choices. Removing StatsComponent from the game entirely was of little help - Stats Component variable on instances was greyed out and set to ‘None’.
Eventually, after some heavy tinkering, updating the engine, tinkering and saving a bit more and finally giving up and re-creating assets, StatsComponent started to spawn correctly for a few launches. Then it broke again.
What I (and many others) found out was that the value for the new component pointer has been overwritten by the Blueprint class CDO. (testTriangleWander is a Bot blueprint)

I couldn’t reproduce the issue on a clean game with this class inheritance arrangement. My next guess is cyclic dependencies in blueprints, but I haven’t yet found any. Is casting to Bot inside Character blueprint considered a cyclic dependency?
Also, I should mention that I have occasional failures on saving a map (externally referenced error) or a blueprint (same here, externally referenced material instances mostly). But these are easy as pie to fix. Sometimes I have “LogUObjectGlobals:Warning: Failed to find object ‘Class None.’” logged to me once but I haven’t tracked it down yet.
I’m workin on this for about 3 days straight and the deeper I go, the more cryptic it seems to me. I have decided to take a break from this issue for a day before trying harder :slight_smile: I am now compiling the bleeding edge engine for rurther testing.

Text version of pseudocode for convenience:



//StatsComponent.h
class UStatsComponent : public UActorComponent
{
	GENERATED_BODY()
public:
	UStatsComponent(const class FObjectInitializer& ObjectInitializer);
	/** character stats, with items and power-ups applied. */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Stats)
	class URPGStats* Stats; //bare UObject child
}

//StatsComponent.cpp
UStatsComponent::UStatsComponent(const class FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
{
	Stats = NewObject<URPGStats>(this);
	check(Stats); //always valid
}

//MyCharacter.h
class AMyCharacter : public ACharacter
{
	GENERATED_BODY()
public:
	/** Character stats managing component */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Stats)
	class UStatsComponent* StatsComponent;
}

//MyCharacter.cpp
AMyCharacter::AMyCharacter(const class FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
{
	StatsComponent = ObjectInitializer.CreateDefaultSubobject<UStatsComponent>(this, TEXT("CharacterStats"));
	check(StatsComponent); //always valid here
}

//MyBot.h
class AMyBot : public AMyCharacter
{
	GENERATED_BODY()
public:
	AMyBot(const class FObjectInitializer& ObjectInitializer);
protected:
	void BeginPlay() override;
}

//MyBot.cpp
AMyBot::AMyBot(const class FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
{
	check(StatsComponent); //always valid
}

void AMyBot::BeginPlay()
{
	check(StatsComponent); //!CRASH
}


1 Like

Thanks for the info. To supplement your advice, in order for the components to be private members marked as UPROPERTYs, the parameter meta = (AllowPrivateAccess = “true”) is required. Otherwise, a compiler error will be produced:

Is there any documentation on the meta specifiers for UPROPERTY? I searched several times for this, but couldn’t find anything.

The biggest thing that stands out is this:


//StatsComponent.cpp
UStatsComponent::UStatsComponent(const class FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
{
	Stats = **NewObject<URPGStats>(this)**;
	check(Stats); //always valid
}

Objects constructed in this fashion will not have the proper flags set that mark it as a subobject for serialization. I suspect what is happening here is that the constructor is invoked, then in ~FObjectInitializer, property values are serialized in. Since Stats is not properly marked as a subobject, it has no serialized value and ends up being zeroed out. See if you absolutely need a subobject, something like “stats” is usually best represented as a struct. Especially in this case where StatsComponent seems to be just a container for the stats data. If you do want an object, then make use of that object initializer and use CreateDefaultSubobject. You will also need to mark the Stats property as Instanced, otherwise all your stats components will share the same Stats subobject.

Now, that probably doesn’t explain why the StatsComponent itself is getting reset to null. Most likely Blueprint serialization is involved. Have you tried recreating a different blueprint from scratch to see if it also happens? If it persists, use a data breakpoint to see when it’s being overwritten. (In Visual Studio, use the debugger to break in UStatsComponent::UStatsComponent, right after Stats is assigned. Then in the breakpoints window, use New Data Breakpoint and provide &Stats.) The debugger should break when the value gets overwritten, which may or may not help clarifying. My educated guess is that it will break inside FObjectInitializer::~FObjectInitializer, in InitProperties or possibly InstanceSubobjects.

Creating subobjects inline is finnicky and certainly doesn’t work for components. You shouldn’t be trying to use the drop down menu, but should rather be using the yellow arrow to revert to defaults. But if the Blueprint’s default object is serialized with a null component, as seems to be the case, then the default value for your blueprint is in fact null and using the yellow arrow (if it even shows up) will just revert to None. You would have to fix this by reverting the blueprint defaults to that of the native base class.

Unfortunately, this is where my experience breaks down – I’ve never confirmed where the serialized data for blueprint CDOs lies. Since they are an asset type, my theory is that they go through the DDC (derived data cache) like all other assets. When I last had issues serializing blueprint defaults, I fiddled with lots of different things like recompiling, resaving, recreating, as well as deleting the contents of the DDC. I’m not sure which part worked but the DDC might be worth a try. Delete or rename the DerivedDataCache folder for your game project, you might also have to do it for the Engine DerivedDataCache folder.

Edit: Well ****, I just realized I already said most of this about the DDC earlier in this thread.

You’ll find most of them in ObjectBase.h. But unlike the class/property/function keywords, metadata keywords aren’t lexically parsed by the header tool, so they don’t need a definition in ObjectBase and therefore get forgotten from time to time… As AllowPrivateAccess was. For the most part, they can be figured out by searching the codebase to see how they are used, though.

Same issue with creating a custom CharacterMovementComponent, which was used with an Character BP.
I changed the C++ class filename and classnames of the CMC in two subsequent steps, which seemed to have thrown off the UE build system, parent Actor BPs initializing the CMC properly, but on beginPlay() the CMC property was null.

Creating a new Character BP from scratch, with the same CMC solved it.

I ran into the exact same issue here, when an ability system component (ASC) was added in C++ to the project’s base Character class. When an existing Character subclass that derived from the project’s base Character was opened in the editor, the component would exist in the ‘Components’ tab however the details would not populate under the Details tab when the component was selected, and in-game the component would be null.

Similarly to what Babymaster3000 posted, I reparented the Character subclass to the default Character (ACharacter) class, and then re-reparented the Character subclass back to the project’s base Character class. After the reparent the ASC populated details of the Details tab and the in-game value of the component was valid.

2 Likes

You absolute legend, this is exactly the problem I’ve been having for days now. The same solution of reparenting the character worked perfectly, thank you so much!

2 Likes

Hi, guys.

I’m facing the same problem in UE 5.0.3.
The base C++ class is working properly, but if I inherit a bluprint from the base C++ class, then the properties of child actors are reset to default values.
The study of the code in the debugger showed that at first the properties of child actors are loaded correctly - this can be seen if override virtual PostLoad() method of the child actors. But then the child actors are recreated again several times, and after first recreation their properties are reset to default values.

Perhaps it has something to do with world partition or level streaming.

Also, I noticed that the child actors have the bNeedsRecreate flag set in the PostLoad() method.

I have been trying to solve this problem for several days.
Using TWeakObjectPtr doesn’t help.
Marking properties as private, BlueprintReadOnly and VisibleAnywhere also doesn’t helps.

I specifically installed the engine version 4.27 to see, how it nativize a similar bluprint to C++ code, and found an interesting moment there - setting the flags when creating new object:

ABP_ConnectableSplineConnection_C__pf3944188905::StaticClass()->GetDefaultObject();
auto __Local__7 = NewObject<ABP_ConnectableSplineConnection_C__pf3944188905>(InDynamicClass, ABP_ConnectableSplineConnection_C__pf3944188905::StaticClass(), TEXT("BP_TestBlueprint2_GEN_VARIABLE_BP_TestBlueprint2_C_CAT"), (EObjectFlags)0x00280029);
InDynamicClass->MiscConvertedSubobjects.Add(__Local__7);
auto& __Local__8 = (*(AccessPrivateProperty<EActorUpdateOverlapsMethod >((__Local__7), AActor::__PPO__DefaultUpdateOverlapsMethodDuringLevelStreaming() )));
__Local__8 = EActorUpdateOverlapsMethod::OnlyUpdateMovable;

I haven’t figured out which flags are being set yet.

(EObjectFlags)0x00280029 == RF_Public | RF_Transactional | RF_ArchetypeObject | RF_WasLoaded | RF_LoadCompleted

It looks like I figured out what’s going on:
In order for the properties of components to be saved when loading the level, it is necessary that they are created in the actor constructor, and their CreationMethod must be equal to EComponentCreationMethod::Native (this value is set by default when creating a new component using CrteateDefaultSubobject()).
If components are created in the OnConstruction() method and their CreationMethod = EComponentCreationMethod::UserConstructionScript, then they are recreated after loading, because when loading, the values of the actor properties are loaded, which causes the re-creation of all the actor components that have CreationMethod = EComponentCreationMethod::UserConstructionScript.

1 Like

Still here in 5.0.3, sometimes I hate Epic

I’m facing the same problem and my solution is rename the member variable. Lucky for me, the variable only used in Cpp and easy to rename it.

1 Like

7 years later and this is still here. Workaround is not practical for big projects. Unreal, sort it!

3 Likes