http://androidxref.com/8.1.0_r33/xref/system/chre/util/include/chre/util/singleton.h

继承关系

屏幕快照 2020-05-27 下午8.40.43.png

设计分析

CRTP模式

在这里,CRTP模式的意图是利用编译器会根据泛型类型生成模板代码的特性,来为每一个继承自Singleton并将泛型类型指定为自身的类生成一套这个类专用的static方法,这是一种编译时代码生成技术,C++模板的本质就是编译时代码生成。这样,就可以避免为每一个单例类写一套相同的单例逻辑。

禁止Copy

单例类对象应该禁止copy构造函数和赋值操作符,这是通过继承另一个基类NonCopyable实现的。

没有完全禁止构造

虽然NonCopyable禁止了拷贝构造和赋值,但它并没有禁止调用构造函数,甚至还显示保留了public的默认构造函数。因此,使用方需要确保总是使用static方法get来获取单例对象,确保不自己调用单例类的构造函数。

实现分析

  1. // singleton_impl.h文件内容
  2. #ifndef CHRE_UTIL_SINGLETON_IMPL_H_
  3. #define CHRE_UTIL_SINGLETON_IMPL_H_
  4. #include <utility>
  5. #include "chre/util/singleton.h"
  6. namespace chre {
  7. // 记住static属性在class中仅仅是声明,而不是定义,这里才是定义
  8. //
  9. // 一般来说static定义必须写在实现文件中,而不是头文件中,如果写在头文件,就必须确保这个头文件不会被
  10. // 多次包含,否则会产生重复定义符号的链接错误。不过,对于模板编译器有单独的规则,编译器多次遇到模板代
  11. // 码时,虽然每次都会生成代码,但不会因为定义重复而报错,否则C++模板就根本无法使用了。
  12. // 参考:https://stackoverflow.com/questions/3229883/static-member-initialization-in-a-class-template
  13. template<typename ObjectType>
  14. typename std::aligned_storage<sizeof(ObjectType), alignof(ObjectType)>::type
  15. Singleton<ObjectType>::sObject;
  16. // static属性定义
  17. template<typename ObjectType>
  18. bool Singleton<ObjectType>::sIsInitialized = false;
  19. // 应用模板,可以让init适配任意ObjectType类型定义的构造函数参数
  20. template<typename ObjectType>
  21. template<typename... Args>
  22. void Singleton<ObjectType>::init(Args&&... args) {
  23. if (!sIsInitialized) {
  24. sIsInitialized = true;
  25. new (get()) ObjectType(std::forward<Args>(args)...);
  26. }
  27. }
  28. template<typename ObjectType>
  29. void Singleton<ObjectType>::deinit() {
  30. if (sIsInitialized) {
  31. get()->~ObjectType();
  32. sIsInitialized = false;
  33. }
  34. }
  35. template<typename ObjectType>
  36. bool Singleton<ObjectType>::isInitialized() {
  37. return sIsInitialized;
  38. }
  39. // 按照设计,get之前必须先通过init完成初始化,直接调用get会返回nullptr
  40. template<typename ObjectType>
  41. ObjectType *Singleton<ObjectType>::get() {
  42. if (sIsInitialized) {
  43. return reinterpret_cast<ObjectType *>(&sObject);
  44. } else {
  45. return nullptr;
  46. }
  47. }
  48. } // namespace chre
  49. #endif // CHRE_UTIL_SINGLETON_IMPL_H_