【问题标题】:Ensuring that a static method gets called before main()确保在 main() 之前调用静态方法
【发布时间】:2011-06-03 00:53:44
【问题描述】:

我有一个工人类的集合,我需要能够用一个工厂动态地构造这些类的实例。这背后的原因是经常编写新的工人类,我宁愿每次添加新的工人类时都不必为每个工人类型更新工厂类。

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

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

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

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

我希望在构造类的任何实例之前初始化静态变量。当工作类被编译成包含main() 的相同二进制文件时,这似乎工作得很好。但是,当FooWorker 在库中(比如libblahapp_workers.a)并且主可执行文件链接该库时,看起来_dummyInstanceRegistrationVariable 直到main() 启动后才被初始化(我假设它在第一个实例FooWorker 已构建),这对我的目的来说太迟了。

我还尝试在全局范围内构造一个WorkerImplementationRegisterer&lt;T&gt; 对象,该对象在构造时注册适当的工作类型,但是当工作类位于main() 外部的库中时,我又遇到了问题;在 main() 开始之前不会构造全局范围的对象。

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

【问题讨论】:

标签: c++


【解决方案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;
...

这是我的意思的一个非常基本的版本,但希望你能理解。

【讨论】:

  • 感谢您的建议。不幸的是,这种方法对我不起作用。这里的主要问题是 FooWorker 应该在 构造任何 FooWorker 实例之前向 WorkerImplementationList 注册。
【解决方案3】:

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

static ios_base::Init __ioinit;

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-10-22
    • 2021-03-30
    • 2013-04-24
    • 1970-01-01
    • 1970-01-01
    • 2014-08-25
    • 2016-07-29
    相关资源
    最近更新 更多