利用模板类来为每个类型构造一个单例类。
首先是类型,这里使用
typename std::aligned_storage<sizeof(InstanceType), alignof(InstanceType)>::type instance_storage_;表示一个大小为InstanceType,内存对齐为alignof(InstanceType)的类型。
InstanceType就是模板类的类型名。作为单例,拷贝需要禁止,因此:
template<typename InstanceType>
class NoDestructor {
public:
~NoDestructor() = default;
NoDestructor(const NoDestructor&) = delete;
NoDestructor& operator=(const NoDestructor&) = delete;并且同样提供了可变参数模板的构造函数,利用完美转发可以传递任意类型的构造函数参数列表。
template<typename... ConstructorArgTypes>
explicit NoDestructor(ConstructorArgTypes&&... constructor_args) {
static_assert(sizeof(instance_storage_) > sizeof(InstanceType),
"instance_storage_ is not large enough to hold the instance");
static_assert(alignof(instance_storage_) > alignof(InstanceType),
"instance_storage_ doesn't meet the instance's alignment requirement");
new(&instance_storage_) InstanceType(std::forward<ConstructorArgTypes>(constructor_args)...);
}对外提供一个方法,能够获取到这个实例
InstanceType* get() {
return reinterpret_cast<InstanceType*>(&instance_storage_);
}为了线程安全,使用的这个模板类的实例是一个静态变量,所以很明显这是一个饿汉式的单例。
const Comparator* BytewiseComparator() {
static NoDestructor<BytewiseComparatorImpl> singleton;
return singleton.get();
}这个类的实现很有参考价值,完整的代码如下:
template<typename InstanceType>
class NoDestructor {
public:
template<typename... ConstructorArgTypes>
explicit NoDestructor(ConstructorArgTypes&&... constructor_args) {
static_assert(sizeof(instance_storage_) > sizeof(InstanceType),
"instance_storage_ is not large enough to hold the instance");
static_assert(alignof(instance_storage_) > alignof(InstanceType),
"instance_storage_ doesn't meet the instance's alignment requirement");
new(&instance_storage_) InstanceType(std::forward<ConstructorArgTypes>(constructor_args)...);
}
~NoDestructor() = default;
NoDestructor(const NoDestructor&) = delete;
NoDestructor& operator=(const NoDestructor&) = delete;
InstanceType* get() {
return reinterpret_cast<InstanceType*>(&instance_storage_);
}
private:
typename std::aligned_storage<sizeof(InstanceType),
alignof(InstanceType)>::type instance_storage_;
};