UObject get deleted just after being created

Hello,

(I am new to Uneral C++ so it is maybe very obvious)
I have a class derived from Character and I use a class derived from UOjbect and FTickableGameObject to handle his life : UPROPERTY() UResource* LifeResource . However, when I use LifeResource = NewObject() in my character contructor to set his life, my pointer LifeResource is set to null, so I suppose I must prevent the garbage collector to delete it, but how ? I thought an UPROPERTY() pointer would count as a hard reference.

MyCharacter.h file :

#pragma once

#include "GameFramework/Character.h"
#include "Resource.h"
#include "MyCharacter.generated.h"

UCLASS()
class PROTOTYPEFPS_API AMyCharacter : public ACharacter
{
	GENERATED_BODY()

public:
	// Sets default values for this character's properties
	AMyCharacter();

	// Called when the game starts or when spawned
	virtual void BeginPlay() override;
	
	// Called every frame
	virtual void Tick(float DeltaSeconds) override;

	// Called to bind functionality to input
	virtual void SetupPlayerInputComponent(class UInputComponent* InputComponent) override;

	UPROPERTY()
	UResource* LifeResource;

	UPROPERTY(EditAnywhere)
	int32 LifePoints;
	
};

MyCharacter.cpp file :

#include "PrototypeFPS.h"
#include "MyCharacter.h"
#include "Resource.h"

// Sets default values
AMyCharacter::AMyCharacter()
{
	// Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

	LifePoints = 250;

	LifeResource = NewObject<UResource>();
	LifeResource->ResetMaxValue(LifePoints);

}

// Called when the game starts or when spawned
void AMyCharacter::BeginPlay()
{
	Super::BeginPlay();
	
}

// Called every frame
void AMyCharacter::Tick( float DeltaTime )
{
	Super::Tick( DeltaTime );

	if (GEngine && LifeResource) {
		GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, FString::SanitizeFloat(LifeResource->ActualValue));
	}
	else if (!LifeResource) {
		GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT("Shrek is love"));
	}
}

// Called to bind functionality to input
void AMyCharacter::SetupPlayerInputComponent(class UInputComponent* InputComponent)
{
	Super::SetupPlayerInputComponent(InputComponent);

}

There is nothing special in UResource, I override FTickableGameObject like that :

virtual void Tick(float DeltaTime) override;

virtual bool IsTickable() const override;

virtual TStatId GetStatId() const override;

then

void UResource::Tick(float DeltaTime)
{
	ActualValue += DeltaTime * Regeneration;
	FMath::Clamp(ActualValue, ValueMin, ValueMax);
}

bool UResource::IsTickable() const
{
	return true;
}

TStatId UResource::GetStatId() const
{
	return Super::GetStatID();
}

Any ideas ? Thanks for reading :slight_smile:

If it can help : I tried to call LifeResource = NewObject(this) but then the unreal editor crashed everytime. Here are the UResource files :

Resource.h file :

#pragma once

#include "Object.h"
#include "Resource.generated.h"

/**
 * Main class for cooldowns, life and similar attributes
 */
UCLASS(Blueprintable)
class PROTOTYPEFPS_API UResource : public UObject, public FTickableGameObject
{
	GENERATED_BODY()
public:

	UPROPERTY(EditAnywhere)
	float ValueMin;

	UPROPERTY(EditAnywhere)
	float ValueMax;

	UPROPERTY(EditAnywhere)
	float InitValue;

	UPROPERTY(EditAnywhere)
	float Regeneration;

	UPROPERTY()
	float ActualValue;

	UResource();
	
	// Override FTickableGameObject functions

	virtual void Tick(float DeltaTime) override;

	virtual bool IsTickable() const override;

	virtual TStatId GetStatId() const override;

	UFUNCTION()
	void AddValue(float Value);

	UFUNCTION()
	bool IsEmpty() const;

	UFUNCTION()
	bool IsFull() const;

	UFUNCTION()
	void ResetMaxValue(float NewMax);

};

Resource.cpp file :

#include "PrototypeFPS.h"
#include "Resource.h"

UResource::UResource()
{
	ValueMin = 0;
	ValueMax = 100;
	InitValue = 100;
	Regeneration = 1;

	FMath::Clamp(InitValue, ValueMin, ValueMax);

	ActualValue = InitValue;
}

void UResource::Tick(float DeltaTime)
{
	ActualValue += DeltaTime * Regeneration;
	FMath::Clamp(ActualValue, ValueMin, ValueMax);
}

bool UResource::IsTickable() const
{
	return true;
}

TStatId UResource::GetStatId() const
{
	return Super::GetStatID();
}

void UResource::AddValue(float Value)
{
	ActualValue += Value;
	FMath::Clamp(ActualValue, ValueMin, ValueMax);
}

bool UResource::IsEmpty() const
{
	return (ValueMin == ActualValue);
}

bool UResource::IsFull() const
{
	return (ValueMax == ActualValue);
}

void UResource::ResetMaxValue(float NewMax)
{
	if (InitValue == ValueMax) {
		InitValue = NewMax;
	}

	ValueMax = NewMax;

	ActualValue = InitValue;
	FMath::Clamp(ActualValue, ValueMin, ValueMax);
}

Hey I can see a few issues with your code, garbage collection is not the problem as far as I can tell.

1. Use are using NewOjbect<>() incorrectly.

The correct use for you is:

LifeResource = NewObject<UResource>(this, UResource::StaticClass());

You need this so the object knows which world is belongs to and who it’s owner is. UResource::StaticClass() is the actual class you want to instantiate.

2. If that doesn’t completely fix your problem, try moving the NewObject<>() code to BeginPlay() or PostInitProperties()

The constructor in Unreal is a bit odd, since it is called by the editor to create the Class Default Object (CDO).

I didn’t read the rest of your code, so let me know if there are any more problems.

hey, thanks !

I placed the NewObject() in BeginPlay and it worked fine, but adding UResource::StaticClass() and this or not seems to change nothing (I thoght they were the default parameter).

The crash with the code compiled with “this” as parameter isn’t happening when NewObject() is in BeginPlay, so I suppose that “this” isn’t defined yet in the constructor (a bit odd yes).

Do you know when PostInitProperties() is called (compared to the constructor and BeginPlay) ?

Thanks again, it helps me a lot

PostInitProperties() is called after the constructor and before BeginPlay.