Initiliazing UObject as UProperty in inherted class of ACharacter

Hello for all!
I’ve implemented class, that inherited from UObject. I want to add an instance of it to another class as UProperty field. I know that it must be pointer and I know that it must be initialized by NewObject. But I can’t figure out why this field is not valid in Blueprint if I initialized it in constructor. But this field is valid, when I initialized it in event BeginPlay.

Class inherited from UObject

UCLASS(Blueprintable,  BlueprintType)
class MYPROJECT3_API UCInventory : public UObject
{
    GENERATED_BODY()
public:
    UCInventory();
};

UCInventory::UCInventory() : Super() {}

Class that contains instance of above class

UCLASS()
class MYPROJECT3_API ACBaseCharacter : public ACharacter
{
    GENERATED_BODY()

public:
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = General)
    UCInventory * inventory;
}

ACBaseCharacter::ACBaseCharacter(const FObjectInitializer& ObjectInitializer) :Super(ObjectInitializer)
{
    inventory = NewObject<UCInventory>();
}

Try CreateDefaultSubobject when called in the constructor, see this question for clarification. e.g.

inventory = ObjectInitializer.CreateDefaultSubobject(this, TEXT("Inventory"));

NB: You should pass in this in the outer when you use NewObject so it won’t be garbage collected, unless you want to create a temporary variable. e.g.

inventory = NewObject(this);

When I try to pass this to NewObject, I get a segfault. Something wrong?

I’ve tried create by ObjectInitializer.CreateDefaultSubobject(this, TEXT("Inventory")); it works fine. I’ve read answer, that you’ve pointed, but I want to clarify. Will be object, created by ObjectInitializer::CreateDefaultSubobject, under GC?

Yes CreateDefaultSubobject + UProperty will ensure the variable remains available for the lifetime of the parent object.

Not sure why you’re segfaulting, perhaps its the custom constructor you’ve made. You shouldn’t need to define one as GENERATED_UCLASS_BODY() will make the default

UCInventory::UCInventory(const class FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer){
}

available

Ok, problem has been solved, but I’m not sure, that GENARATED_BODY will make by default. I’ve comment it, and I’ve got compilation error, which contains this Expected a GENERATED_UCLASS_BODY() at the start of class

Try using GENERATED_UCLASS_BODY() instead of GENERATED_BODY()

It makes no difference to me. I get an segfault. I can show log message. Fatal error: [File:D:\BuildFarm\buildmachine_++depot+UE4-Releases+4.9\Engine\Source\Runtime\CoreUObject\Private\UObject\UObjectGlobals.cpp] [Line: 2637] NewObject with empty name can't be used to create default subobjects (inside of UObject derived class constructor) as it produces inconsistent object names. Use ObjectInitializer.CreateDefaultSuobject<> instead.

I’ve tried to pass this and TEXT("Inventory") and it works. It works even with GENERATED_BODY. And it is valid. I can assume, that for instatiating objects of UObject, we need pass Outer and Name. E. g. NewObject(this, TEXT("Inventory")).

Thank you very much!

Yep the error message is consistent, the engine needs consistent object naming. Not sure why but I’m guessing it has to do with reflection and introspection.

Everything in constructor will be used in constructing Class Default Object, so you should not create any object in constructor, other then CreateDefaultSubobject which usally is used for component creation

But why not just?

UCLASS()
class MYPROJECT3_API ACBaseCharacter : public ACharacter
{
    GENERATED_BODY()

public:
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = General)
    UCInventory * Inventory;

    UPROPERTY(BlueprintReadWrite, Category = General)
    TSubclassOf<UCInventory> InventoryClass;

    virtual void BeginPlay() override;
}

ACBaseCharacter::ACBaseCharacter(const FObjectInitializer& ObjectInitializer) :Super(ObjectInitializer)
{
}

void ACBaseCharacter::BeginPlay() {
     Inventory = NewObject<UCInventory>(this,InventoryClass);
}

If you want to create default inventory, then consider creating array of UClasses (can be TSubclassOf) and fill inventory with items in array by spawning them and adding to inventory.

BeginPlay event was made for gameplay actor initiation, so don’t be shy to use it for init stuff.

Thank you very much for explaination!