Can't initialize a static object

Hello everyone. I’m trying to create a singleton object to hold the current game time in my game. I want all of my objects to have access to it. My code looks like this:

UClock.h

#include "Object.h"
#include "Clock.generated.h"

/**
 * 
 */
UCLASS(BlueprintType)
class BARON_API UClock : public UObject
{
	GENERATED_UCLASS_BODY()

public:
	UFUNCTION(BlueprintCallable, Category = "Function")
	void incrementTime();
	UFUNCTION(BlueprintCallable, Category = "Function")
		static UClock* getClockInstance();

	UPROPERTY(BlueprintReadWrite, Category = "Time")
		int32 minutes;
	UPROPERTY(BlueprintReadWrite, Category = "Time")
		int32 hours;
	UPROPERTY(BlueprintReadWrite, Category = "Time")
		int32 Seconds;
	UPROPERTY(BlueprintReadWrite, Category = "Time")
		int32 days;
	UPROPERTY(BlueprintReadWrite, Category = "Time")
		int32 years;
	UPROPERTY(BlueprintReadWrite, Category = "Time")
		int32 seasons;
};

Uclock.cpp

UClock::UClock(const class FPostConstructInitializeProperties& PCIP)
	: Super(PCIP)
{
	Seconds = 0;
	minutes = 0;
	hours = 8;
	days = 1;
	years = 1440;
	seasons = 0;
}
void UClock::incrementTime()
{
//stuff
}
UClock* UClock::getClockInstance()
{
	static UClock* clock;
	if (!clock || !IsValid(clock))
	{
		UClass *SingletonClass = LoadClass<UObject>(NULL, TEXT("/Script/ModuleName.Clock"), NULL, LOAD_None, NULL);
		clock = (UClock*)ConstructObject<UObject>(SingletonClass);
	}
	return clock;
}

So in my level blueprint, i call this function to get a reference to my clock object, but it crashes upon start up, saying that ConstructObject used a NULL object.

I think it may have to do with LoadClass, and the path i provided in the 2nd argument. What exactly am i supposed to put there for it to work?

No, is that what i need to do? Do i create a new BP in my game and have it inherit from UClock?

1 Like

Okay I did that. I got it working in my Level blueprint. But when I tried to use it in my other blueprint, it crashed the game on startup. Its saying i have a fatal error.

It seems to work if i only have one instance of it. When i try to use it twice in two different BPs, it fails.

You are aware of FDateTime?

There also FTimespan for time spans

Yes but i need some different functionality. I just need help with the instantiation of the static object.

So SingletonClass is a blueprint?

Try using UClock::StaticClass() instd of playing with LoadClass(). very UOBject based class already have UClass generated and can b accesed via static function StaticClass().

Also try moving clock vrable from local scope.

Do I still need to ConstructObject? Where should I move the clock variable? If it’s static, it shouldn’t matter, right?

Static variables exist throughout the lifetime of the program. It should be fine where it is, but ill move it just to test it.

Very strange. I got it working using StaticClass and ConstructObject, and i played my game and it worked fine. But i tried playing again, but it crashes because of an assert for a IsValidLowLevel()
.

Tried 5 times in a row and it failed on the fifth time with no changes.

I think perhaps my static pointer is not getting deleted properly or something. I set a breakpoint on the checking if valid call. I found that on my second time pressing start, my pointer already had a memory address set, and my game proceeded to crash… What should I do?

I think I have it fixed. I have changed this:

UClock* UClock::getClockInstance()
{
	static UClock* clock;
	if (clock ==nullptr || !clock->IsValidLowLevel())
	{
		UClass *Clockclass = UClock::StaticClass();
		clock = (UClock*) ConstructObject<UObject>(Clockclass);
	}
	return clock;
}

Enjoy, for any future people :slight_smile:

well it does matter, local scope varables are destroued when function is done… atleast i think, moce it to class scope. Also use ConstructObject, yes

My {guess} is that the UObject gets destroyed by unreal, but your pointer does not because static variables in C++ do not get cleared as you might expect.

If you added a destructor that clears your pointer then your previous code would likely have worked.

Its generally cleaner (faster, fewer unexpected sideeffects to simple looking code, fewer bugs in the long run) to instantiate singleton objects outside the accessor (say in some static init function you call on game mode BeginPlay), and assign and clear singleton pointers in the constructor and destructor.