2011-03-15 169 views
4

这涉及到的对象在C初始化++模仿C++静态构造函数

我有一组类(没有实例),从一个共同的基类继承,我需要他们登记有关信息问题他们自己在一个容器(特别是地图)中,当程序启动时。

问题是我需要它是动态的。容器在独立项目中定义,与类不同。我宁愿避免制作多个硬编码版本的库,每个程序使用它的每一组类都有一个版本。

我想过在这些子类的每一个中都有一个特殊类的静态实例,这会在其构造函数中进行注册。但是,我发现没有办法保证在建造这些物品之前集装箱将被建造。

我还应该注意,在创建这些子类的任何实例之前,容器中关于子类的信息应该可用。

有没有办法做到这一点,或模仿C++中的静态构造函数?

+0

你不能让注册表对象(地图),其通过的getInstance动态创建一个单身()? – Kevin 2011-03-15 18:51:16

回答

1

您正在一次描述不同的问题。在某种类型的静态初始化的特定问题上,一种简单的方法是创建一个将执行注册的伪类。然后,每一个不同的类都可以有一个static const X成员,成员必须在翻译单元中定义,并且定义将触发实例的实例化和类的注册。

这并没有解决难以解决的问题,这是创始化命令的失败。该语言不对任何翻译单元中对象的初始化顺序提供任何保证。也就是说,如果你用这样的类编译三个翻译单元,则不能保证假成员的相对执行顺序。这也适用于库:如果这样的容器是全局/静态成员属性,则不能保证你想要注册类的容器已经被初始化。

如果您有权访问该代码,则可以修改容器代码以使用static local variables,这将向前迈出一步,以确保初始化顺序。作为一个可能的解决方案的草图:

// 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 

现在,在这种情况下,是ab类的登记中没有明确的命令,但可能不会是一个问题。在另一方面,通过在registry::instance功能使用局部静态变量单例的初始化保证要被执行之前registry::register方法中的任何呼叫(作为第一呼叫到instance方法的一部分)。

如果你不能做出改变,你基本上运气不好,你不能保证registry将在其他翻译单元中的其他静态成员属性(或全局变量)之前实例化。如果是这样的话,那么你将不得不推迟该类的注册到第一个实例化,并且将代码添加到要注册的每个类的构造函数中,以确保该类在之前在对象的实际构造之前注册了

这可能或不是解决方案,具体取决于其他代码是否创建类型的对象。在工厂函数的特定情况下(首先想到的是),如果没有其他东西被允许创建类型为ab的对象...则构造函数调用中的小猪支持注册也不是解决方案。

+0

谢谢。这看起来像我在找什么。至于最后一件事,你是否指的是编译器可能会忽略编译类的可能性,如果它不是在某处构建的? – Chris 2011-03-15 19:25:29

+0

不是真的,而是因为如果没有关于代码的功能的信息,很难判断是否实际上在其他地方实例化了这些类型的对象。如果你的代码没有创建'a'的对象,那么向'a'构造函数添加注册调用将没有任何作用 - 没有调用的构造函数=>不执行注册 – 2011-03-15 20:13:56

0

这是Singleton pattern的候选人。基本上,您希望容器在实例化子类的第一个实例时被实例化。这可以通过检查基类构造函数中的单例指针是否为NULL来实现,如果是,则实例化容器。

0

其中一个想法是将注册仿函数传递给类。每个后代都会执行该功能进行注册。这个仿函数可以在构造函数中传递。

实施例:

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"); 
    } 
}; 
0

参见:http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.14

一种选择是懒惰地,当第一件事被添加到它构造容器:

void AddToContainer(...) { 
    // Will be initialized the first time this function is called. 
    static Container* c = new Container(); 
    c->Add(...); 
    } 

的唯一方法“模仿“一个静态构造函数是显式调用一个函数来执行你的静态初始化。仅通过链接模块,没有其他方式可以在代码之前运行代码。

1

它反对OOP范式,但如何让静态成员形成由2个全局变量引导的链表?你可以做这样的事情:

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 

相信全局变量,因为他们不需要有构造,但都只是纯粹的数据,保证当你开始进行初始化已执行你的代码。

显然这不是线程安全的等,但应该使你的工作完成。

0

您可能会使用“initialise on first use”模式,然后实例化一个虚拟静态实例,以确保尽早进行初始化。

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 ;