Post by Marcel Muellerstatic vector<const ET_File_Description*> ETFileDescription;
struct ET_File_Description
{
ET_File_Description()
{ ETFileDescription.push_back(this);
}
// several function pointers with file type specific handlers...
};
const struct Asf_Description : ET_File_Description
{ Asf_Description()
{ // assign the function pointers...
}
}
ASF_Description();
This declares a function, probably not what you wanted. Assuming you
wanted to define a static variable instead.
You publish the pointer in the global ETFileDescription before the most
derived object is constructed. Not a good idea in a multithreading
environment, the object should be published to other threads only after
it has been properly initialized. Also, if registration of objects can
be multithreaded, the push_back operation would need a mutex lock.
At least in the past global static initialization used the be
single-threaded and appeared before main(), but nowadays I'm not so
sure, the standard speaks about deferred initialization which can happen
after main() and in different threads.
Thread-safety is not the only one of your worries. A more serious
problem is that the global statics suffer from the static initialization
order fiasco, meaning that the global ETFileDescription in the first TU
is not guaranteed to be constructed before a static Asf_Description is
constructed in another TU.
Curiously, in case the implementation uses deferred initialization, it
is obliged to get the initialization order correct.
So, with some implementations you may suffer from initialization order
fiasco, and with other implementations you may suffer from
multithreading issues.
Suggesting to wrap ETFileDescription in a function as a local static,
this makes the behavior much more determined, it will be initialized by
the first call of the function.
Alternatively, I gather one can use C++20 modules and import
declarations to enforce proper order of translation units.
Post by Marcel MuellerMay the different static initializers run in parallel?
Looks like yes, at least if deferred initialization is used by the
implementation.
Post by Marcel MuellerMay a compiler elide the global variables since they are not used directly?
If deferred initialization is used, they might be never constructed
indeed, and I gather in this case the compiler may elide them indeed.
Even without deferred initialization, if the TU does not define any
symbols with external linkage, the whole TU can be discarded AFAIK,
together with the "unused" global variable.
I do not know if any current C++ implementation actually supports this
deferred initialization for non-local statics. Seems like a pretty
disruptive change.
In short, it looks like this is yet another case study of why global
statics are bad, and it looks like they have gone worse recently. Better
to avoid them, or at least make the registration functions explicit and
placed in the beginning of main().