我有一组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
)并且主可执行文件链接到该库时,_dummyInstanceRegistrationVariable
在main()
启动之后才会初始化{I} {假设它是在构造FooWorker
的第一个实例时初始化的,这对我的目的来说太晚了。
我还尝试在全局范围内构造一个WorkerImplementationRegisterer<T>
对象,在构造它时注册适当的工作类型,但是当工作类位于{{1}外部的库中时,我再次遇到问题}; <{1}}开始之前不会构建全局范围的对象。
静态链接我的工作者库会解决这个问题吗?我缺少一个更优雅的解决方案吗?任何你能给我的帮助都将不胜感激。
答案 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的实现,它可能会给你一些想法。