2012-12-11 12 views
6

Registrazione automatica di classe in C++ è un compito comune, e una domanda più frequenti qui su StackOverflow:scalabile registrazione della classe automatica in C++

Register an object creator in object factory

Somehow register my classes in a list

automatic registration of object creator function with a macro

c++ automatic factory registration of derived types

L'obiettivo di base è registrare er classi automaticamente con qualche registro o fabbrica in modo che possa fare un po 'di lavoro con ogni classe più tardi.

Questa è una tecnica consolidata, utilizzata da librerie come (ad esempio) Google Test (http://code.google.com/p/googletest), che registra automaticamente sottoclassi della classe Test in modo che ogni test possa essere istanziato automaticamente ed essere eseguito durante l'esecuzione del test.

La registrazione può essere eseguita istanziando una classe di registrazione statica il cui costruttore esegue la registrazione, o mediante un uso intelligente del CRTP e inserendo il codice di registrazione nel costruttore della classe base o qualsiasi altra cosa desiderata (i collegamenti sopra riportati offrono diversi possibili tecniche).

Tuttavia, quando implemento una di queste tecniche, trovo che si ridimensiona molto male. Se in Google Test sono presenti 10.000 richiami di macro di TEST, la compilazione e il collegamento si arrestano (MSVC 2010) e le dimensioni binarie esplodono. Se implemento questo in un altro modo, usando 10.000 sottoclassi con registrar statici, vedo lo stesso comportamento.

Ad esempio, si consideri l'esempio semplificato:

#include <iostream> 
#include <string> 

class Base { 

    public: 

     Base(const std::string& Name_) : Name(Name_) { ; } 
     ~Base() { ; } 

     virtual std::string GetName() const { return Name; } 
     virtual void DoSomething() = 0; 

    private: 

     std::string Name; 

}; 

class Registry { 

    public: 

     static Registry& GetInstance() { 
      static Registry* Instance = new Registry(); 
      return *Instance; 
     } 

     void Register(const Base* b) { 
      std::cout << "Registered class " << b->GetName() << std::endl; 
     } 

    private: 

     Registry() { ; } 
     ~Registry() { ; } 

}; 

class Registrar { 

    public: 

     Registrar(const Base* b) { 
      Registry::GetInstance().Register(b); 
     } 

     ~Registrar() { } 

}; 


#define REGISTER(CLASS)           \ 
    class CLASS : public Base {          \ 
     public:              \ 
      CLASS(const std::string& Name) : Base(Name) { ; } \ 
      virtual void DoSomething();        \ 
     private:             \ 
      static Registrar m_Registrar;       \ 
    };                \ 
    Registrar CLASS::m_Registrar(new CLASS(#CLASS));   \ 
    void CLASS::DoSomething() 


int main(int argc, char** argv) 
{ 
    return 0; 
} 


REGISTER(Class1) 
{ 
    std::cout << "Doing something in Class1" << std::endl; 
} 

REGISTER(Class2) 
{ 
    std::cout << "Doing something in Class2" << std::endl; 
} 

[...] 

con un totale di 10000 chiamate REGISTRO generati automaticamente.

Esiste un motivo fondamentale per cui questo non si adatta bene? Il compilatore si strozzerà solo su 10000 classi? Sotto MSVC 2010 la compilazione di quanto sopra richiede quasi due minuti su una macchina abbastanza veloce e produce un binario di dimensioni superiori a 5 MB. Se faccio lo stesso con Google Test, vedo lo stesso risultato.

+2

Si prega di prestare attenzione alla differenza tra un 'class' e un' oggetto'. Questo codice ** non ** registra le classi (e non dovrebbe), registra ** oggetti **. –

+0

Grazie Pete. Per il mio scopo, come per Google Test, ci sarà una mappatura uno-a-uno così posso scegliere una tecnica che registri entrambi, ma il tuo punto è ben preso. – DSII

+1

No, senza un ** grande ** sforzo, non è possibile registrare le classi. –

risposta

1

Scrivere codice Java in C++ funziona raramente. Tutte quelle allocazioni di heap sono probabilmente le prestazioni di uccisione (come in Java, ma l'avvio di Java è così lento che nessuno potrebbe accorgersene). Usa oggetti statici e non mettere un oggetto Registrar in ogni classe generata; è solo uno spreco di tempo e spazio.

+0

Grazie Pete - ma ci ho provato, e non aiuta. Potrebbe ridurre di 15 secondi il tempo di compilazione di 2 minuti e 200 kB di un file binario da 5 MB. Le prestazioni di runtime non sono il problema; tutte le implementazioni che ho provato sono abbastanza veloci. – DSII

+0

Giusto per essere chiari, stai praticamente suggerendo di avere singole istanze statiche di ogni classe derivata, e fare in modo che il costruttore della classe base esegua la registrazione, giusto? L'ho provato e si comporta in modo identico. – DSII

+0

Oh, stai parlando del tempo di compilazione? No, non penso che ci sia molto che puoi fare lì. La registrazione automatica dipende dalla costruzione di oggetti e ciò significa creare un oggetto per tutto ciò che deve essere registrato. –

Problemi correlati