I have a class with some static members, and I want to run some code to initialize them (suppose this code cannot be converted into a simple expression). In Java, I would just do
class MyClass { static int myDatum; static { /* do some computation which sets myDatum */ } }
Unless I'm mistaken, C++ does not allow for such static code blocks, right? What should I be doing instead?
I would like solution for both of the following options:
For the second option, I was thinking of:
class StaticInitialized { static bool staticsInitialized = false; virtual void initializeStatics(); StaticInitialized() { if (!staticsInitialized) { initializeStatics(); staticsInitialized = true; } } }; class MyClass : private StaticInitialized { static int myDatum; void initializeStatics() { /* computation which sets myDatum */ } };
but that's not possible, since C++ (at the moment?) does not allow initialization of non-const static members. But, at least that reduces the problem of a static block to that of static initialization by expression...
There is no concept with the name "static block" in C/C++. Java has it however, a "static block" is an initializer code block for a class which runs exactly once, before the first instance of a class is created.
In a Java class, a static block is a set of instructions that is run only once when a class is loaded into memory. A static block is also called a static initialization block. This is because it is an option for initializing or setting up the class at run-time.
Static methods belong to the class and they will be loaded into the memory along with the class, you can invoke them without creating an object. (using the class name as reference). Whereas a static block is a block of code with a static keyword. In general, these are used to initialize the static members.
You can use Class. forName("com. the. ClassName"); to call static block without ceating any instance of that class.
For #1, if you really need to initialise when the process starts/library is loaded, you'll have to use something platform-specific (such as DllMain on Windows).
However, if it's enough for you to run the initialisation before any code from the same .cpp file as the statics is executed, the following should work:
// Header: class MyClass { static int myDatum; static int initDatum(); };
// .cpp file: int MyClass::myDatum = MyClass::initDatum();
This way, initDatum()
is guaranteed to be called before any code from that .cpp
file is executed.
If you don't want to pollute the class definition, you can also use a Lambda (C++11):
// Header: class MyClass { static int myDatum; };
// .cpp file: int MyClass::myDatum = []() -> int { /*any code here*/ return /*something*/; }();
Don't forget the last pair of parentheses - that actually calls the lambda.
As for #2, there's one problem: you can't call a virtual function in the constructor. You're better off doing this by hand in the class instead of using a base class for it:
class MyClass { static int myDatum; MyClass() { static bool onlyOnce = []() -> bool { MyClass::myDatum = /*whatever*/; return true; } } };
Assuming the class only has one constructor, that will work just fine; it is thread-safe, as C++11 guarantees such safety for initializing static local variables.
It turns out we can implement a Java-style static block, albeit outside of a class rather than inside it, i.e. at translation unit scope. The implementation is a bit ugly under the hood, but when used it's quite elegant!
There's now a GitHub repo for the solution, containing a single header file: static_block.hpp
.
If you write:
static_block { std::cout << "Hello static block world!\n"; }
this code will run before your main()
. And you can initialize static variables or do whatever else you like. So you can place such a block in your class' .cpp
implementation file.
Notes:
The static block implementation involves a dummy variable initialized statically with a function. Your static block is actually the body of that function. To ensure we don't collide with some other dummy variable (e.g. from another static block - or anywhere else), we need a bit of macro machinery.
#define CONCATENATE(s1, s2) s1##s2 #define EXPAND_THEN_CONCATENATE(s1, s2) CONCATENATE(s1, s2) #ifdef __COUNTER__ #define UNIQUE_IDENTIFIER(prefix) EXPAND_THEN_CONCATENATE(prefix, __COUNTER__) #else #define UNIQUE_IDENTIFIER(prefix) EXPAND_THEN_CONCATENATE(prefix, __LINE__) #endif // __COUNTER__ #ifdef _MSC_VER #define _UNUSED #else #define _UNUSED __attribute((unused)) #endif // _MSC_VER
and here is the macro work to put things together:
#define static_block STATIC_BLOCK_IMPL1(UNIQUE_IDENTIFIER(_static_block_)) #define STATIC_BLOCK_IMPL1(prefix) \ STATIC_BLOCK_IMPL2(CONCATENATE(prefix,_fn),CONCATENATE(prefix,_var)) #define STATIC_BLOCK_IMPL2(function_name,var_name) \ static void function_name(); \ static int var_name _UNUSED = (function_name(), 0) ; \ static void function_name()
Notes:
__COUNTER__
- it's not part of the C++ standard; in those cases the code above uses __LINE__
, which works too. GCC and Clang do support __COUNTER__
.__attribute ((unused))
might be dropped, or replaced with [[unused]]
if you have a C++11 compiler which doesn't like the GCC-style unused extension.main()
, you are not guaranteed when exactly that happens relative to other static initializations.Live Demo
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With