静态编译有其优势,但有些情况下,静态编译反而会造成一些不便。
工厂类注册问题
工厂类一般使用模板或宏的方式,如下列代码申明:
class ExpressionFactoryRegisterer
{
public:
ExpressionFactoryRegisterer(const std::string &name, const ExpressionFactoryPtr &factory)
{
GetExpressionTable()->RegisterExpressionFactory(name, factory);
}
};
#define REGISTER_EXPRESSION_CONCAT_IMPL(a, b) a##b
#define REGISTER_EXPRESSION_CONCAT(a, b) REGISTER_EXPRESSION_CONCAT_IMPL(a, b)
#define REGISTER_EXPRESSION_FACTORY(name, factory) \
namespace \
{ \
BS_NAMESPACE(expression)::ExpressionFactoryRegisterer \
REGISTER_EXPRESSION_CONCAT(r, __COUNTER__)(name, factory); \
}
#define REGISTER_EXPRESSION_TYPE(name, type) \
namespace \
{ \
BS_NAMESPACE(expression)::ExpressionFactoryRegisterer REGISTER_EXPRESSION_CONCAT(r, __COUNTER__)( \
name, std::make_shared<BS_NAMESPACE(expression)::TypedExpressionFactory<type>>()); \
}
代码注册如下:
REGISTER_EXPRESSION_FACTORY("log", std::make_shared<UnaryMathExpressionFactory<Func__log>>());
这样注册之后,一个简单的"反射"机制建立起来。但一般情况下,为了避免多重定义,会降代码注册的部分写到 .cc
文件中,但静态编译的时候, .cc
生成的 .o
文件,会通过 ar
工具打包成 .a
文件,此时 .a
文件直接去链接,静态区过程会滞后,导致 RegisterExpressionFactory
动作变成运行态执行。当程序真正执行时,初始化从静态区获取不到注册的类,导致空结果或指针。
正确的方式有2种:
这样程序会再链接的时候,将注册内容真正的放入静态区,程序启动时,直接加载到对应变量中,就不会为空啦。