Initialize static variables

Hi all,

How can I have static blocks of code that will be executed only once?

I know how to initialize variables like this:

//HEADER
static const FName ActionName_Collect;
//CPP
const FName UMyClass::ActionName_Collect = FName("Collect");

And that works, but, if I want a struct that doesn’t have a Constructor with all the parameters, I will need to initialize it in code.

//HEADER
static FInputModeGameAndUI MyInputMode;
//C++

static_block_that_is_called_once
{
	UMyClass::MyInputMode.SetLockMouseToViewportBehavior(EMouseLockMode::DoNotLock);
	UMyClass::MyInputMode.SetHideCursorDuringCapture(false);
}

I would like to do something like this:



Is that possible in Unreal? How would you initialize static variables?

Sorry, Is not that I need to do this but I can’t shake off 15 years of Java development even though I’ve been exclusively working with UE4 the last 6.

Thanks!

Hi!

The short answer - you always have to initialize static variables. If a struct doesn’t have a proper constructor you will need to inizialize it’s variables. I don’t thing that keeping InputMode struct as a static (probably global?) thing is a good idea anyway. I’d rather create a singleton object that handles all input modes. It will also make them unique and initialized once. More about singletons in c++ here: c++ - Singleton: How should it be used - Stack Overflow
(yeah, I know that singletons are devil, but this IS the situation it fits perfectly).

The LOOOONG answer:
The first thing that needs to be understand is what statics in c++ are and how c++ is compiled. In C++ there is a concept of headers and source files, but in the end only source files are compiled and headers are glued to source files (via #include). One source file with included headers is compiled into something called a translation unit.
That leads to a situation that one header can be used in two different source files. That means we will have a two different translation units. Both of them will have a static variable, with the same name, BUT they will be two different variables, because of a rule that a that static variable in c++ is a variable that is initialized ONLY once. This is why you need to initialize them in c++ file :slight_smile:

In your example from stack overflow there is a static block but it is defined in c++ file, so i t won’t be accessed for other files.

Hope this whole lecture helped :smiley:

Hi Zombpi, thanks for your thorough answer.

Yes, I am aware of Singletons and I use them when the situation is required (or subsysems, which if find them more convenient for Blueprints).

In this case, I wanted to have variables that all instances of the same class will use (a controller in this particular case but can be any). It is basically nothing the amount of memory and CPU that saves, so it’s not about optimization. But, for instance, I normally put FNames, FStrings, floats, int32s, FCollisionShapes etc as static members if all the instanced objects are going to use the same data. I have also seen this among the engine code, (you can see static FName MeshComponentName; in Character.h). So i wondered, knowing that we can not extend Structs, and some structs don’t have constructors with all the parameters,if there was a way to do this. As I said, I used to work with java and c# and I used to have static members inside classes if all the objects were going to be using the same data. Having it outside the class, in a singleton, in my humble opinion, can be against encapsulation and creates a bit of inter-dependency.

Sorry for my long comment, but anyhow, I don’t see any problem in having non-static variables in each object, so I don’t really care if I don’t find a solution, I would just stick to non-static variables and initialize them in the constructor.

Thanks again for you thorough answer.

Hi again! I was thinking more and, sorry, but didn’t catch the “with all the parameters” part. FInputModeGameAndUI has default constructor indeed but not with parameters.

Now I can see - there are 2 options you can do such initialization.

1 - because FInputModeGameAndUI has setters which returns references to itself in cpp file you can do such a thing:

FInputModeGameAndUI UMyClass::MyInputMode = FInputModeGameAndUI().SetWidgetToFocus(nullptr).SetLockMouseToViewportBehavior(EMouseLockMode::DoNotLock).SetHideCursorDuringCapture(false);

2 - you can create a default input mode and init it somewhere in begin play or PostInitProperties:

FInputModeGameAndUI UMyClass::MyInputMode = {};

void UMyClass::PostInitProperties()
{
    Super::PostInitProperties();

    static bool bStaticInit = false; // will be set to false only once
    if (bStaticInit == false)
    {
        bStaticInit = true;
        MyInputMode.SetLockMouseToViewportBehavior(EMouseLockMode::DoNotLock);
        MyInputMode.SetHideCursorDuringCapture(false);
    }

Sorry if I didn’t explain myself correctly, I’d say that English is not my first language as an excuse but I explain myself even worse in my native language :slight_smile:

Beautiful, works like a charm! I forgot that setters return the reference. I can even make it “static const” now!

Second option is quite cool too, didn’t realize of that either.

You just upgraded my brain firmware. Thanks very much!