Imitate a static constructor in C++
这是一个与C++中对象初始化有关的问题。
我有一组类(不是实例),继承自一个公共的基类,当程序启动时,我需要它们在一个容器(特别是一个映射)中注册关于它们自己的信息。
问题是我需要它是动态的。容器是在独立的项目中定义的,与类不同。我希望避免生成库的多个硬编码版本,每个使用库的程序中的每一组类都有一个硬编码版本。
我考虑在每个子类中都有一个特殊类的静态实例,这样就可以在其构造函数中注册。但是,我找不到任何方法来保证容器在建造这些对象之前就已经建造好了。
我还应该注意,在创建这些子类的任何实例之前,容器中关于子类的信息应该是可用的。
有没有办法做到这一点,或者模仿C++中的静态构造函数?
型
这是反对OOP范式的,但是让静态成员组成一个由2个全局变量引导的链接列表怎么样?你可以这样做:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ClassRegistrator *head=NULL; ClassRegistrator *tail=NULL; struct ClassRegistrator { ... //data that you need ClassRegistrator *next; ClassRegistrator(classData ...) { if (head==NULL) head=tail=this; else { tail->next=this; tail=this; } ... //do other stuff that you need for registration } }; class MyClass { //the class you want to register static ClassRegistrator registrator; } ClassRegistrator MyClass::registrator(...); //call the constructor |
。
我相信全局变量,因为它们不需要有一个构造函数,但只是纯数据,所以在开始执行代码时,它们肯定已经初始化了。
显然,这不是线程安全的,等等,但应该让您的工作完成。
型
你在同时描述不同的问题。对于某些静态初始化的特殊问题,一种简单的方法是创建一个将执行注册的假类。然后,每个不同的类都可以有一个
这并不能解决困难的问题,那就是初始秩序的崩溃。语言不能保证不同翻译单元中对象的初始化顺序。也就是说,如果用这样的类编译三个翻译单元,就不能保证假成员的相对执行顺序。这也适用于库:如果要在其中注册类的容器是全局/静态成员属性,则不保证该容器已初始化。
如果您有权访问代码,可以修改容器代码以使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | // registry lib class registry { // basically a singleton public: static registry& instance() { // ensures initialization in the first call static registry inst; return inst; } // rest of the code private: registry(); // disable other code from constructing elements of this type }; // register.h struct register { template <typename T> register( std::string name ) { registry::instance().register( name, T (*factory)() ); // or whatever you need to register } }; // a.h class a { public: static a* factory(); private: static const register r; }; // a.cpp const register a::r("class a", a::factory ); // b.h/b.cpp similar to a.h/a.cpp |
在这种情况下,
如果您不能进行这种更改,那么您基本上是运气不好,并且您不能保证在其他翻译单元中的其他静态成员属性(或全局属性)之前实例化
这可能是一个解决方案,具体取决于其他代码是否创建该类型的对象。在工厂功能的特殊情况下(首先想到的),如果不允许任何其他东西创建
型
您可以使用"首次使用时初始化"模式,然后实例化一个虚拟静态实例以确保尽早初始化。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | class cExample { public : cExample() ; // Static functions here private : static bool static_init ; // other static members here } cExample::static init = false ; cExample::cExample() { // Static initialisation on first use if( !static_init ) { // initialise static members } // Instance initialisation here (if needed) } // Dummy instance to force initialisation before main() (if necessary) static cExample force_init ; |
型
请参阅:http://www. PARASIFIF.COM/C++-FAQLIT/Ctos.
一种选择是,当第一件事添加到容器中时,惰性地构造容器:
1 2 3 4 5 | void AddToContainer(...) { // Will be initialized the first time this function is called. static Container* c = new Container(); c->Add(...); } |
号
"模仿"静态构造函数的唯一方法是显式调用函数来执行静态初始化。只有在模块中链接才能运行代码pre-main。
型
一种方法是将注册函数传递给类。每个后代将执行要注册的函数。此函数可以在构造函数中传递。
例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | struct Registration_Interface { virtual void operator() (const std::string& component_name) = 0; }; struct Base { }; struct Child1 : public Base { Child(Registration_Interface& registration_ftor) { //... registration_ftor("Child1"); } }; |
型
这是单例模式的候选者。基本上,当子类的第一个实例被实例化时,您希望容器被实例化。这可以通过检查基类构造函数中的单例指针是否为空来实现,如果为空,则实例化容器。