2012-12-11 36 views
6

自動類註冊是一種常見的任務,在這裏一個常見的問題在計算器上:可擴展的自動化類註冊在C++中的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

基本目標是註冊呃類自動與一些註冊表或工廠,以便它可以在以後每個類的一些工作。

這是一個非常成熟的技術,被Google Test(http://code.google.com/p/googletest)等圖書館使用,可以自動註冊Test類的子類,以便每個測試都可以自動實例化並在測試執行期間運行。

註冊可以通過實例化一個靜態註冊器類來實現,註冊器類的構造函數執行註冊,或者通過巧妙使用CRTP並將註冊代碼放入基類構造器或任何你喜歡的東西(上面的鏈接提供了幾種不同的可能技術)。

但是,當我實施這些技術時,我發現它們的比例很差。如果我在Google Test中有10,000個TEST宏調用,編譯和鏈接就會停​​頓(MSVC 2010),並且二進制大小會爆炸。如果我以另一種方式實現這一點,則使用具有靜態註冊器的10,000個子類,我會看到相同的行爲。

例如,考慮簡化的例子:共有10000個自動生成的註冊電話

#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; 
} 

[...] 

有沒有一個根本原因,爲什麼這不會擴展好?編譯器會扼殺10000個類嗎?在MSVC 2010下編譯上述代碼在一臺相當快的機器上花費了將近兩分鐘的時間,並且生成了一個大小超過5 MB的二進制文件。如果我與谷歌測試類似,我會看到相同的結果。

+2

請注意'class'和'object'之間的區別。此代碼不**註冊類(也不應該),它註冊**對象**。 –

+0

謝謝皮特。就我的目的而言,對於Google Test,我們將會有一對一的映射,因此我可以選擇一種技術來註冊,但您的觀點已被充分利用。 – DSII

+1

不,如果沒有**的努力,你不能註冊課程。 –

回答

1

用C++編寫Java代碼很少效果。所有這些堆分配都可能是殺死性能的原因(就像他們在Java中那樣,但是Java啓動速度太慢以至於沒有人會注意到)。使用靜態對象,並且不要將Registrar對象放入每個生成的類;那只是浪費時間和空間。

+0

謝謝皮特 - 但我已經嘗試過了,並沒有幫助。編譯時間爲2分鐘可能需要15秒,而5 MB二進制文件需要200 kB。運行時性能不是問題;我試過的任何實現都運行得足夠快。 – DSII

+0

爲了清楚起見,你基本上建議每個派生類具有單個靜態實例,並且讓基類構造函數進行註冊,對吧?我確實已經嘗試過了,它的表現完全相同。 – DSII

+0

哦,你說的是編譯時間?不,我不認爲你在那裏可以做很多事情。自動註冊取決於對象的構造,這意味着爲需要註冊的所有內容創建一個對象。 –