开发者

Ensuring that a static method gets called before main()

开发者 https://www.devze.com 2023-03-10 14:48 出处:网络
I have a collection of worker classes, and I need to be able to construct instances of these classes dynamically with a single factory. The reasoning behind this is that new worker classes are written

I have a collection of worker classes, and I need to be able to construct instances of these classes dynamically with a single factory. The reasoning behind this is that new worker classes are written frequently and I'd rather not have to update a factory class per worker type every time I add a new worker class.

The way that this currently works is as follows: I've got a class called WorkerImpleme开发者_高级运维ntationList with a static method:

template <typename T>
    WorkerImplementationList::registerWorkerFactoryMethod<T>(const std::string&)

that stores a pointer to T::newInstance in an internal data structure that will be retrieved by the factory later. In each of the worker classes have a static int called _dummyInstanceRegistrationVariable. In each of the worker classes' .cc files, I have the following line (using FooWorker as an example):

int FooWorker::_dummyInstanceRegistrationVariable =
    WorkerImplementationList::registerWorkerFactoryMethod<FooWorker>("FooWorker");

What I'd like to have happen is for the static variable to be initialized before any instances of the class are constructed. This seems to work just fine when the worker class is compiled into the same binary that contains main(). However, when FooWorker is in a library (say libblahapp_workers.a) and the main executable links that library, it looks like _dummyInstanceRegistrationVariable isn't initialized until after main() starts (I assume it's initialized when the first instance of FooWorker is constructed), which is too late for my purposes.

I've also tried constructing a WorkerImplementationRegisterer<T> object in global scope that registers the appropriate worker type when it's constructed, but here again I run into problems when the worker class is in a library external to main(); that globally-scoped object isn't constructed before main() begins.

Would statically linking my worker libraries solve this problem? Is there a more elegant solution that I'm missing? Any help you could give me would be greatly appreciated.


This sounds like the linker pulling in only the objects it needs, and not pulling in the one with the global variable. Then the global simply doesn't exist, so initialization order is a moot point.

It's a real problem with static libraries, with no universal solution.

Armed with the knowledge that the linker grabs an entire compilation unit from the library at once (on all systems I've seen), you can probably figure out some way to put this global variable into a compilation unit that's needed.


I find its usually best not to assume anything will run before main and and to try not to force that. The best way I find to implement these this is to initialise on first call. I would create a static method in FooWorker called create and construct all instances of FooWorker through that static method. The first thing the create method should do is check to see if FooWorker::_dummyInstanceRegistrationVariable has been initialised and if it hasn't, initialise it.

For example:

main.cc

...
#include <FooWorker.hh>
...

int main(){
   ...
   FooWorker *fw = FooWorker::create(...);
   ...
   delete fw;
   ...
}

FooWorker.hh

...
class FooWorker{
  ...
  static int _dummyInstanceRegistrationVariable;
  ...
  FooWorker *create(/*args*/){
     if(_dummyInstanceRegistrationVariable == 0)
        _dummyInstanceRegistrationVariable = WorkerImplementationList::registerWorkerFactoryMethod<FooWorker>("FooWorker");
     ...
  }
  ...
};
...

FooWorker.cc

...
#include "FooWorker.hh"
...
int FooWorker::_dummyInstanceRegistrationVariable = 0;
...

That's a very basic version of what I mean, but hopefully you get the drift.


iostreams in libstdc++ use file scope static variable for this. In iostream header you can find

static ios_base::Init __ioinit;

definition which takes care of iostreams initialization in constructor (including cin, cout, cerr). See the implementation of ios_base::Init, it may give you some ideas to work with.

0

精彩评论

暂无评论...
验证码 换一张
取 消