Download

Static Const Variable Issue

Have an issue I’m trying to find a workaround for.

I am trying to create static const variables of my data table UAssets. The issue I have isn’t with the syntax, but rather with the use of a USTRUCT that I define in my game module. Everything compiles fine but when I launch the game it crashes with an error saying that the necessary struct that the data table inherits from has yet to be created. This only happens if I use structs that are defined within my game module – if I try to use an engine struct it works fine. I tried playing around with the loading phase of the main game module which solved that one issue, but then a substantial amount of other issues arose which makes me think it’s not advisable to change the main game module’s loading phase.

Basically my issue is that I can create static const variables using engine classes/structs, but if I try to use my own classes/structs, the code will compile fine but the game will crash on launch saying that those classes have yet to be loaded/found Is there a way around this or is this just an inherent issue due to the order in which classes/assets are loaded?

You might be missing some constructor. More shall be revealed by surveying the code.

I’m not at my office right now w/ the actual code but it’s really just as simple as the following:

Header file (in class MyClass):

static const UDataTable* MyDataTable;

CPP file

const MyClass::MyDataTable = Cast<UDataTable>(StaticLoadObject(UDataTable::StaticClass(), nullptr, TEXT("/path/to/asset"));

I don’t want to get too hung up on the data table asset because the issue seems to be my use of game classes/structs I define vs those the engine defines. Like I said the code compiles fine, it just gives an error/crash on launch because that data table uses a struct that I define elsewhere in my game code, as opposed a struct that is engine defined. It’s definitely not an issue with the asset path since if I load it later as a non-static-const it loads fine.

Also just to give another example that’s not related to data tables. The following works fine:

static const TSubclassOf<ACharacter> MyCharacter;
const MyClass::MyCharacter = ACharacter::StaticClass();

However this gives me the same crashing issue:

static const TSubclassOf<ACustomCharacter> MyCustomCharacter;
const MyClass::MyCustomCharacter = ACustomCharacter::StaticClass()

The crash according to the log is because the ACustomCharacter has not yet been loaded/found. The only difference between these 2 things is that ACharacter is an engine-defined class while ACustomCharacter is a class defined in my game module

Yes, this is likely do to the order the modules are loaded. Engine DLLs are loaded before game DLLs. You can tweak that order using LoadingPhase variable in your module: ELoadingPhase::Type | Unreal Engine Documentation

However, I would strongly advise against using static const for anything other than simple data types (PODs - ints, floats, etc) where possible. You’re better off just creating a singleton through the Subsystem Interface (or write your own) and just use encapsulation to keep things const (e.g. the singleton only returns a const version of whatever variable). That way you are within the normal UE loading flow rather than trying to do things at static initialization time.

The main reason I wanted these was to use in a handful of static methods I have that retrieve data table rows. Right now the static methods have to take in a world context object which is then used to navigate to the necessary data table pointer, but it’s kind of a hacky workaround since it in many ways defeats the purpose of having static methods. If I had the tables stored in static const variables I could grab them a lot more easily from the static methods.

A temporary workaround I found is rather than doing:

static const UDataTable*

I can do:

**static const TSoftObjectPtr<UDataTable> **and just point it to my uasset.

This will prevent the crashes described above but then I have to constantly make sure that the TSoftObjectPtr is valid and load it if necessary, which is not ideal.

The UDataTable is going to be constantly cleaned up because you have nothing holding on to the reference. So you’ll need to add it to the root or some such to prevent garbage collection after you load it.

I would still suggest writing a singleton or wrapping that value some how so you have better control over the lifetime / initialization / clean up. Object Lifetime can be one of the bigger headaches in UE4 if you don’t do it properly.

Yeah that’s kind of what I meant above when I said I’d have to constantly load it – I figured the GC would just purge that table every minute or whenever and it’s stupid to keep reloading it over and over again.

Maybe I just need to reevaluate the approach to this like you’re saying, probably not worth trying to fight the engine so much.