The "Instanced" flag for UPROPERTY

I’m having problems with this, maybe I don’t understand exactly what it’s supposed to do. UE Docs page.
From this description I imagine it works like this:

  1. I create an UPROPERTY with this flag. Example:


// AWeapon.h
UPROPERTY(Instanced, EditDefaultsOnly, Category=FireMode)
TSubclassOf<UFireMode> FireModeClass;

  1. This is editable directly in the Weapon blueprint in the editor, I don’t need to create an extra Blueprint based on the fire mode or anything.
  2. Now, editing it like in 2 only works if it’s a “TSubclassOf” which means in C++ this is a type, not an instance, which again means I can’t directly use it but need to instance it first.
  3. So I take the type/class and instance it like this:

UFireMode* FireMode = ConstructObject<class UFireMode>(FireModeClass);

  1. Now I’d imagine this takes the edited properties (the changes I made in the blueprint) and gives me an instance with those. But it doesn’t, all the properties are returned to UFireMode’s default values.
  2. BUT, if I get the default object for FireModeClass the values are exactly what I set in the Blueprint.

Am I missing something here?

I also tried constructing the object like this:


UFireMode* FireMode = ConstructObject<class UFireMode>(FireModeClass, (UObject*)GetTransientPackage(), NAME_None, RF_NoFlags, FireModeClass->GetDefaultObject());

where I pass the edited default object as Template to the ConstructObject method but this doesn’t change anything.

2 Likes

Behind the scenes, the Instanced keyword sets multiple flags on the UProperty. The meaning of it can be a bit confusing, so let me qualify with an example:



	UPROPERTY( Category=Test, EditDefaultsOnly )
	UTexture2D* TestAsset;

	UPROPERTY( Category=Test, EditDefaultsOnly )
	UStaticMeshComponent* TestComponent;


Given an actor with these properties, these two subobjects look and feel very much the same, but are actually very different. In the case of an asset like a texture, if you have 10 different actors using the same texture, you don’t want 10 copies of the same texture. Conversely, you do want the same 10 actors to have their own copy of the component.

The former is not Instanced, while the latter is.

Normally, instanced is the kind of behaviour that you want to be the same for all properties of a certain type, which is why there is a class keyword for it: DefaultToInstanced. You can also set it on a per property basis, and this is the Instanced property keyword.

(Note: In 4.5, I’ve had issues where just the class keyword isn’t enough and have had to add the Instanced keyword to get subobjects to instantiate like I want them to.)

In any event, using Instanced for a UClass property (as is a TSubclassOf) makes little sense. Different instances of the same UClass won’t yield different results – you use them to construct a UObject and all these newly constructed objects will use the same CDO to initialize their properties.

If you want to instantiate a UFireMode for your class and set its own properties, you might have more luck trying a different approach:


UPROPERTY(Instanced, EditDefaultsOnly, Category=FireMode)
UFireMode* FireMode;

This might seem impractical since you’d require some instance of UFireMode to edit. So add another keyword to UFireMode to enable some handy new behaviour:


UCLASS(DefaultToInstanced, **EditInlineNew**)
class UFireMode
{
    ...
};

What EditInlineNew does, essentially, is allow you to create and edit instances of that class “inline”, i.e.: directly in the property editor for them.

Try it out and see if it helps.

13 Likes

Awesome explanation, thanks!
I came to use the Instanced keyword because I tried using EditInline in the UPROPERTY flags but that throws an compiler error telling me to use “Instanced” instead so I used that. I didn’t think to check the UCLASS keywords.
I tested it real quick, the only problem I have right now is it resets to nothing every time I compile the Blueprint.

The short version is that CDO is exactly what it says. Class Default Object. Each blueprint is class, and when set property as instanced, behind the scenes you create instance of this class which have unique properties. GetClassDefaultObject() just return base class, for referenced blueprint.

I disagree. EditInlineNew doesn’t work on Instanced pointers exposed in ActorComponenets for example, and the only work around is to expose TSubclassOf<> and manually create object in code.

Though that’s probably bug not intended behaviour.

I think I understood what cmartel said but I still have the issue of once I click “Play”, the instanced variable is nullptr. I have a detailed question here:

but basically I have the same setup and have successfully set the property to a concrete sub type yet when I click “Player”, it’s back to nullptr. I tried Data breakpoint and it breaks when I set the property and I can see it being not nullptr yet when I click “Play” it’s back to nullptr with no data breakpoint breaking. Why is this happening?

Thank you so much for the detailed explanation!

I had an issue as well with Instanced objects contained in a TArray and saw constant crashes. This is how my simple example looked like.

UCLASS(Abstract, EditInlineNew)
class UMyClass : public UObject
{
  GENERATED_BODY()
	
  UPROPERTY(EditAnywhere, Category = "Dont|Crash")
  uint8 ValueBase;
};

UCLASS()
class UMyClassChild : public UMyClass
{
  GENERATED_BODY()

  UPROPERTY(EditAnywhere, Category = "Dont|Crash")
  uint8 ValueChild;
};

UCLASS()
class SOME_API USomeClass : public UObject
{
  GENERATED_BODY()

  UPROPERTY(Instanced, EditDefaultsOnly, Category = "Dont|Crash")
  TArray<TObjectPtr<UMyClass>> Array;
}

It seems to be that this is an uncovered use case. If I change the Category for the Array to something that is not “Dont|Crash”, then I don’t see any crashes. :muscle:

Or change the categories of your instanced class members. :wink:

EDIT:
It seems to work if you don’t use sub categories with |. Also I saw some weird object editor properties that are not contained in the instanced objects. I don’t recommend using the exact same sub categories like your own object (actor, actor component …).