http://androidxref.com/8.1.0_r33/xref/system/chre/util/include/chre/util/singleton.h
继承关系
设计分析
CRTP模式
在这里,CRTP模式的意图是利用编译器会根据泛型类型生成模板代码的特性,来为每一个继承自Singleton并将泛型类型指定为自身的类生成一套这个类专用的static方法,这是一种编译时代码生成技术,C++模板的本质就是编译时代码生成。这样,就可以避免为每一个单例类写一套相同的单例逻辑。
禁止Copy
单例类对象应该禁止copy构造函数和赋值操作符,这是通过继承另一个基类NonCopyable实现的。
没有完全禁止构造
虽然NonCopyable禁止了拷贝构造和赋值,但它并没有禁止调用构造函数,甚至还显示保留了public的默认构造函数。因此,使用方需要确保总是使用static方法get来获取单例对象,确保不自己调用单例类的构造函数。
实现分析
// singleton_impl.h文件内容
#ifndef CHRE_UTIL_SINGLETON_IMPL_H_
#define CHRE_UTIL_SINGLETON_IMPL_H_
#include <utility>
#include "chre/util/singleton.h"
namespace chre {
// 记住static属性在class中仅仅是声明,而不是定义,这里才是定义
//
// 一般来说static定义必须写在实现文件中,而不是头文件中,如果写在头文件,就必须确保这个头文件不会被
// 多次包含,否则会产生重复定义符号的链接错误。不过,对于模板编译器有单独的规则,编译器多次遇到模板代
// 码时,虽然每次都会生成代码,但不会因为定义重复而报错,否则C++模板就根本无法使用了。
// 参考:https://stackoverflow.com/questions/3229883/static-member-initialization-in-a-class-template
template<typename ObjectType>
typename std::aligned_storage<sizeof(ObjectType), alignof(ObjectType)>::type
Singleton<ObjectType>::sObject;
// static属性定义
template<typename ObjectType>
bool Singleton<ObjectType>::sIsInitialized = false;
// 应用模板,可以让init适配任意ObjectType类型定义的构造函数参数
template<typename ObjectType>
template<typename... Args>
void Singleton<ObjectType>::init(Args&&... args) {
if (!sIsInitialized) {
sIsInitialized = true;
new (get()) ObjectType(std::forward<Args>(args)...);
}
}
template<typename ObjectType>
void Singleton<ObjectType>::deinit() {
if (sIsInitialized) {
get()->~ObjectType();
sIsInitialized = false;
}
}
template<typename ObjectType>
bool Singleton<ObjectType>::isInitialized() {
return sIsInitialized;
}
// 按照设计,get之前必须先通过init完成初始化,直接调用get会返回nullptr
template<typename ObjectType>
ObjectType *Singleton<ObjectType>::get() {
if (sIsInitialized) {
return reinterpret_cast<ObjectType *>(&sObject);
} else {
return nullptr;
}
}
} // namespace chre
#endif // CHRE_UTIL_SINGLETON_IMPL_H_