Instanced subobjects get nulled in a Blueprint class when its parent BP is recompiled.

Instanced object property is being nulled in the editor in a child class when its parent Blueprint is recompiled.

[Attachment Removed]

Steps to Reproduce
1. In code, create an InstancedObject class, based on UObject with EditInlineNew, Blueprintable, DefaultToInstanced specifiers.

2. Create a Blueprint actor class, InstanceOwner.

3. Add a property of InstancedObject type to InstanceOwner and set its default value to non-null.

4. Create a InstanceOwner_Child Blueprint class, based on InstanceOwner.

5. Open both InstanceOwner and InstanceOwner_Child for editing.

6. Recompile InstanceOwner.

7. Observe the value of property added in 3. being nulled in InstanceOwner_Child.

[Attachment Removed]

Hello! Regarding this step:

3. Add a property of InstancedObject type to InstanceOwner and set its default value to non-null.Did you mark that as UPROPERTY(Instanced)? If that wasn’t the problem, can you share your source code?

I’m also reminded of this bugfix CL 44220549 / GitHub commit 5025b6d3b4cf7698c026b2d7facd614dc5c2e9f6, but if you’re on UE 5.7 that should be in your engine version already.

[Attachment Removed]

Hello!

The property is created in a Blueprint class, so to have it instanced, I have marked the subobject’s code class as UCLASS(DefaultToInstanced).

#pragma once
 
#include "CoreMinimal.h"
#include "UObject/Object.h"
#include "InstancedObject.generated.h"
 
/**
 * 
 */
UCLASS(EditInlineNew, Blueprintable, DefaultToInstanced)
class INSTANCEDTEST_API UInstancedObject : public UObject
{
	GENERATED_BODY()
};

I have attached the sample project with 2 Blueprint actor classes to easily reproduce the issue.

[Attachment Removed]

For a instanced subobject to inherit properly, both the object must be marked as instanced - so the class should be marked UCLASS(DefaultToInstanced), but also the owner’s property must be marked instanced - UPROPERTY(Instanced).

As a consequence, blueprint variables aren’t supported to reference an instanced subobject. If you move that to code, things should work correctly.

[Attachment Removed]

Hello, just checking up on your status. Is moving this property to native acceptable in your scenario? And if you’ve had the chance to try it, does it solve the issue?

[Attachment Removed]

Hello! Apologies for the late reply. I have created a C++ wrapper struct containing a UPROPERTY(Instanced) property and I can confirm that adding this struct to my InstanceOwner Actor has fixed the issue. Thank you for the help!

[Attachment Removed]

Hey there! Sorry for taking long to circle back. I was traveling for work and hadn’t asked someone to check up on my cases.

DefaultToInstanced on the UMyClass does automatically cause UnrealHeaderTool to add some PropertyFlags to UPROPERTIES() of that type and derived types. So:

  • UCLASS(DefaultToInstanced) UMyClass
  • Causes UPROPERTY() UMyClass* Foo to automatically have the CPF_InstancedReference, CPF_ExportObject, and EditInline flags/metadata on the FProperty.

That has the following purposes:

  • CPF_InstancedReference: On constructing instances and subclass CDOs, FObjectPropertyBase::InstanceSubobjects knows to create unique subobjects for them, instead of just inheriting pointers to the parent class’s subobjects. You almost always want this for subobjects, hence UActorComponent has UCLASS(DefaultToInstanced).
  • CPF_ExportObject: export the subobject’s value inline on copy/paste and T3D export, instead of exporting the reference (not super relevant)
  • EditInline: Make the properties editable in the details panel

UPROPERTY(Instanced) the specifier similarly adds CPF_InstancedReference, CPF_ExportObject, EditInline. It adds one more property flag, CPF_PersistentInstance, which specifically makes the instanced subobjects they reference get duplicated from the old CDO to new CDO when objects get reinstanced during compiling. In FFindInstancedReferenceSubobjectHelper::Duplicate() the call to GetInstancedSubObjects only considers subobjects pointed to by properties with CPF_PersistentInstance for retaining across BP CDO reinstancing.

My advice has always been to tag both the class and the property. As for your question, the intended use for DefaultToInstanced, this is my take on it:

  • DefaultToInstanced is useful when you know subclasses should always have their own instance of these objects. For example: actor components and custom polymorphic subobjects (your case).
  • The next question (I assume) : shouldn’t DefaultToInstanced automatically lead to CPF_PersistenceInstance as well, for better usability?
    • No, the main reason being that not all subobjects that are DefaultToInstanced should be recreated via the subobject duplication path that CPF_PersistentInstance triggers. Actor components are a counter-example: CreateDefaultSubobject creates them already for native components, SimpleConstructionScript creates them for blueprint added components. They already have their own mechanisms for recreation and retaining modified values.
    • UPROPERTY(Instanced) is for other subobjects that you explicitly want to duplicate, which at the same time ensures its existence across recompiling but also retains their properties.

My rule of thumb: UPROPERTY(Instance) is for when you want the property to own the subobject, so the reference is what persists its existence across recompilation triggered reinstancing.

Final tally:

  • DefaultToInstanced is for when the object should always be instantiated uniquely for subclasses & instances
    • UPROPERTY(Instance) for owned subobjects (for polymorphic configuration)
    • NOT UPROPERTY(Instance) if the subobject is managed by something else, like actor components
  • UPROPERTY(Instance) without DefaultToInstanced if sometimes you want the property to manage the subobject, and sometimes you want it to point at a shared object or asset. That will be more niche I expect.

I hope that helps!

[Attachment Removed]

Glad to help!

[Attachment Removed]

Hello! While my issue has been solved, I was wondering if you could provide me with more clarity about the DefaultToInstanced flag, to avoid misuse in the future.

The official documentation describes it as:

“All instances of this class are considered “instanced”. Instanced classes (components) are duplicated upon construction. This Specifier is inherited by subclasses.”

I initially interpreted it as marking a class as UCLASS(DefaultToInstanced) would be equivalent to all properties referencing this class having UPROPERTY(Instanced) flag automatically added. If this is not the case, then what is the intended use of DefaultToInstanced?

[Attachment Removed]