序列化库依赖于一些静态变量和表格的存在,用于存储与运行时类型相关的信息。例如,这些表格可以将导出的名称与类型相关联,或者将基类与派生类相关联。构建、销毁和使用这些变量需要考虑以下问题:
这个单例实现具有以下特点:
任何实例在尝试访问它之前都会被构建。
namespace boost {
namespace serialization {
template <typename T>
class singleton : public boost::noncopyable
{
public:
static const T & get_const_instance();
static T & get_mutable_instance();
static bool is_destroyed();
};
} // namespace serialization
} // namespace boost
static const T & get_const_instance();:获取此类型的单例的常量引用。
static T & get_mutable_instance();:获取此类型的单例的可变引用。
static bool is_destroyed();:如果此单例的析构函数已被调用,则返回true。否则,返回false。
为了将类型 T 用作 singleton,类型 T 必须具备默认构造能力。它不需要静态变量,尽管它可以拥有静态变量。由于库保证了只有一个 singleton实例,并且所有访问都通过上述静态接口函数进行,T 的普通成员函数成为等效于静态函数的功能性函数。
有至少两种不同的使用此类模板的方式,这两种方式都在序列化库中被使用。
第一种方式由文件 extended_type_info.cpp 中的代码片段进行示例,其中包含以下代码:
typedef std::set ktmap;
...
void
extended_type_info::key_register(const char *key) {
...
result = singleton::get_mutable_instance().insert(this);
...
}
只要在程序中的任何地方引用了单例实例,就可以确保指定类型(例如,在此示例中的 ktmap)的一个且仅有一个实例在整个程序中存在。不需要任何其他的声明或定义。
第二种方式是将 singleton 用作类型的一个基类之一。以下是来自 extended_type_info_typeid.hpp 的简化代码示例:
template<class T>
class extended_type_info_typeid :
public detail::extended_type_info_typeid_0,
public singleton<extended_type_info_typeid<const T> >
{
friend class singleton<extended_type_info_typeid<const T> >;
private:
// 阻止存在除静态实例之外的任何构造函数的私有构造函数。注意:并非所有编译器都支持这一点!!!
extended_type_info_typeid() :
detail::extended_type_info_typeid_0()
{
type_register(typeid(T));
}
~extended_type_info_typeid(){}
...
};
这种用法允许更自然的语法:
extended_type_info_typeid<T>::get_const_instance()
同样,在程序的任何地方包含上述一个或多个语句都会确保创建并引用一个且仅有一个实例。