确保在main()之前调用静态方法

时间:2011-06-03 00:53:44

标签: c++

我有一组worker类,我需要能够使用单个工厂动态构造这些类的实例。这背后的原因是经常编写新的工作类,而且每次添加新的工作类时,我不必更新每个工作类型的工厂类。

目前的工作方式如下:我有一个名为WorkerImplementationList的类,带有静态方法:

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

将指向T::newInstance的指针存储在内部数据结构中,稍后将由工厂检索。在每个worker类中都有一个名为_dummyInstanceRegistrationVariable的静态int。在每个工作类的.cc文件中,我有以下行(以FooWorker为例):

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

我希望发生的是在构造类的任何实例之前初始化静态变量。当worker类被编译为包含main()的相同二进制文件时,这似乎工作得很好。但是,当FooWorker位于库中时(例如libblahapp_workers.a)并且主可执行文件链接到该库时,_dummyInstanceRegistrationVariablemain()启动之后才会初始化{I} {假设它是在构造FooWorker的第一个实例时初始化的,这对我的目的来说太晚了。

我还尝试在全局范围内构造一个WorkerImplementationRegisterer<T>对象,在构造它时注册适当的工作类型,但是当工作类位于{{1}外部的库中时,我再次遇到问题}; <{1}}开始之前不会构建全局范围的对象。

静态链接我的工作者库会解决这个问题吗?我缺少一个更优雅的解决方案吗?任何你能给我的帮助都将不胜感激。

3 个答案:

答案 0 :(得分:3)

这听起来像链接器仅引入它需要的对象,而不是拉入具有全局变量的对象。那么全局根本就不存在,所以初始化顺序是一个没有实际意义的点。

这是静态库的一个真正问题,没有通用解决方案。

知道链接器立即从库中获取整个编译单元(在我见过的所有系统上),你可能想出一些方法将这个全局变量放入需要的编译单元。 / p>

答案 1 :(得分:2)

我发现通常最好不要假设任何事情会在main之前运行,并尽量不强迫它。我发现实现这些的最好方法是在第一次调用时初始化。我将在FooWorker中创建一个名为create的静态方法,并通过该静态方法构造FooWorker的所有实例。 create方法应该做的第一件事是检查FooWorker::_dummyInstanceRegistrationVariable是否已初始化,如果没有,则初始化它。

例如:

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;
...

这是我的意思的一个非常基本的版本,但希望你得到漂移。

答案 2 :(得分:2)

libstdc ++中的iostreams使用文件范围静态变量。在iostream标题中,您可以找到

static ios_base::Init __ioinit;

定义,它负责构造函数中的iostreams初始化(包括cin,cout,cerr)。看看ios_base :: Init的实现,它可能会给你一些想法。