6

C++ 中的自动类注册是一项常见任务,也是 StackOverflow 上的一个常见问题:

在对象工厂中注册对象创建者

以某种方式在列表中注册我的课程

使用宏自动注册对象创建函数

c++派生类型的自动工厂注册

基本目标是向某个注册表或工厂自动注册类,以便以后可以对每个类进行一些工作。

这是一种成熟的技术,被库(例如)Google Test ( http://code.google.com/p/googletest ) 使用,它自动注册 Test 类的子类,以便可以自动实例化每个测试并在测试执行期间运行。

注册可以通过实例化其构造函数进行注册的静态 Registrar 类来完成,或者通过巧妙地使用 CRTP 并将注册代码放入基类构造函数中,或者您喜欢的任何内容(上面的链接提供了几种不同的可能技术)。

然而,当我实现这些技术中的任何一种时,我发现它们的扩展性非常差。如果我在 Google Test 中有 10,000 个 TEST 宏调用,编译和链接就会停​​止(MSVC 2010)并且二进制文件大小会爆炸。如果我以另一种方式实现这一点,使用 10,000 个具有静态注册器的子类,我会看到相同的行为。

例如,考虑简化的示例:

#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 个自动生成的 REGISTER 调用。

这是否有一个根本原因不能很好地扩展?编译器会阻塞 10000 个类吗?在 MSVC 2010 下,在相当快的机器上编译上述代码需要将近两分钟,并生成大小超过 5 MB 的二进制文件。如果我对 Google Test 进行类似操作,我会看到相同的结果。

4

1 回答 1

1

用 C++ 编写 Java 代码很少能奏效。所有这些堆分配可能会扼杀性能(就像在 Java 中那样,但 Java 启动太慢以至于没有人注意到)。使用静态对象,不要将Registrar对象放入每个生成的类中;那只是浪费时间和空间。

于 2012-12-11T16:43:37.940 回答