DSI*_*SII 6 c++ macros templates c-preprocessor
C++中的自动类注册是一项常见任务,这是StackOverflow上常见的问题:
基本目标是自动向某些注册表或工厂注册类,以便以后可以对每个类进行一些工作.
这是一种成熟的技术,由(例如)Google Test(http://code.google.com/p/googletest)等库使用,它自动注册Test类的子类,以便每个测试都可以自动实例化并在测试执行期间运行.
注册可以通过实例化其构造函数进行注册的静态注册器类,或者通过巧妙地使用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;
}
[...]
Run Code Online (Sandbox Code Playgroud)
共有10000个自动生成的REGISTER调用.
有没有一个根本原因,为什么这不会很好地扩展?编译器会阻塞10000个类吗?在MSVC 2010下,上面的编译在一台相当快的机器上花了将近两分钟,并产生一个超过5 MB的二进制文件.如果我与Google Test类似,我会看到相同的结果.
用 C++ 编写 Java 代码很少能奏效。所有这些堆分配可能都会影响性能(就像在 Java 中一样,但 Java 启动速度太慢以至于没有人会注意到)。使用静态对象,不要将Registrar对象放入每个生成的类中;这只是浪费时间和空间。