当前位置:   article > 正文

C++设计模式:单例模式-提供线程安全的单例模板类_类模板单例模式

类模板单例模式
  1. //!
  2. //! C++设计模式: 单例模式-提供线程安全的单例模板类
  3. //!
  4. //! == 单例模式简介 ==
  5. //! 单例模式出现的原因是一个类在整个程序运行时,最多只能存在一个对象,
  6. //! 单例类本身会构造出唯一的对象,并返回指针给使用者,
  7. //! 为了防止使用者自己构造对象,单例类需要将构造函数限制在私有区域
  8. //! 单例类的特性是一个程序只存在一个对象,且可以跨文件提供给使用者,
  9. //! 这意味着单例类与全局变量一样,没有作用域的限制
  10. //! == 单例模式简介 ==
  11. //!
  12. //!
  13. //! == 单例类特点 ==
  14. //! 单例类存在静态创建与动态创建两种方式:
  15. //! 静态创建:在main函数执行前创建,在main函数结束后释放,无论是否使用都会创建对象
  16. //! 动态创建:首次使用时创建,可以手动释放资源,不使用则不创建
  17. //! 动态创建由于创建实际延时到调用时机,会出现多线程问题,需要线程同步,
  18. //! 实际使用默认推荐静态创建,因为如果不使用该单例对象的话,就不应该存在这个文件
  19. //! 如果存在多选一判断的单例类,即多个单例类中最后使用的结果未知,且只使用其中一个,
  20. //! 推荐动态创建,以节约全局资源
  21. //!
  22. //! 单例模板类在使用上分为真单例与伪单例两种用法:
  23. //! 真单例:构造函数私有,外部无法在创建新的对象
  24. //! 伪单例:使用默认构造函数,提供单例对象接口,但外部可以创建对象
  25. //! 当使用者不是自己是,往往需要提供真单例给其他人使用,以防止误操作,
  26. //! 但如果创建与使用单例的但是自己,则推荐伪单例,因为明确知道类的使用方法,
  27. //! 则不强制限制构造函数,非单例但当作单例使用,以达到快速开发的目的
  28. //! == 单例类特点 ==
  29. //!
  30. //!
  31. //! == 应用场景 ==
  32. //! 单例类的唯一对象特性非常适合用于对资源对接,如存在唯一数据库,
  33. //! 或者唯一日志类时的接口封装,且由于没有作用域的限制,
  34. //! 使得被单例类控制的资源可以在全范围使用
  35. //! 单例类无限制作用域的特点是一把双刃剑,即十分灵活也打破了模块封装的壁垒,
  36. //! 如资源需要限制范围时,需谨慎使用单例模式
  37. //! == 应用场景 ==
  38. //!
  39. //! 结束语:
  40. //! 文章在最后提供Tsingle.h文件的单例模板,可供快速建立类,
  41. //! 文章的测试代码直接运行,会导致打印内容混乱,
  42. //! 最后的测试结果已经归纳好了单个test函数的输出结果
  43. //!
  44. #include "Tsingle.h"
  45. #include <iostream>
  46. #include <mutex>
  47. #include <vector>
  48. #include <fstream>
  49. using namespace std;
  50. //===== 单例模式写法 =====
  51. //== 静态创建 ==
  52. //new singleton_s 的静态指针会在进入main函数之前执行,
  53. // exit_class 类的静态对象的析构函数会在main函数执行结束之后调用,
  54. // 利用exit_class析构函数释放singleton_s指针内配的内存
  55. class singleton_s
  56. {
  57. public:
  58. static singleton_s* get() { return _obj; }
  59. void print(string log)
  60. {
  61. cout<<log<<endl;
  62. }
  63. private:
  64. singleton_s()
  65. {
  66. static exit_class exit;
  67. cout<<"in singleton_s"<<endl;
  68. }
  69. ~singleton_s()
  70. {
  71. cout<<"out singleton_s"<<endl;
  72. }
  73. struct exit_class
  74. {
  75. exit_class()
  76. {
  77. cout<<"in exit_class"<<endl;
  78. }
  79. ~exit_class()
  80. {
  81. delete _obj;
  82. cout<<"out exit_class"<<endl;
  83. }
  84. };
  85. static singleton_s *_obj;
  86. };
  87. singleton_s *singleton_s::_obj = new singleton_s;
  88. //== 静态创建 ==
  89. //== 动态创建 ==
  90. //防止多线程创建需要加锁,保证多线程安全
  91. //动态创建通常是为了节约内存,不必要不创建,既提供创建也提供回收
  92. class singleton_d
  93. {
  94. public:
  95. static singleton_d* get()
  96. {
  97. //双重判断加锁提速
  98. if(_obj == nullptr)
  99. {
  100. _mut.lock();
  101. if(_obj == nullptr)
  102. {
  103. _obj = new singleton_d;
  104. }
  105. _mut.unlock();
  106. }
  107. return _obj;
  108. }
  109. void clear()
  110. {
  111. _mut.lock();
  112. delete _obj;
  113. _obj = nullptr;
  114. _mut.unlock();
  115. }
  116. void print(string log)
  117. {
  118. cout<<log<<endl;
  119. }
  120. private:
  121. singleton_d()
  122. {
  123. cout<<"in singleton_d"<<endl;
  124. }
  125. ~singleton_d()
  126. {
  127. cout<<"out singleton_d"<<endl;
  128. }
  129. static singleton_d *_obj;
  130. static std::mutex _mut;
  131. };
  132. singleton_d *singleton_d::_obj = nullptr;
  133. std::mutex singleton_d::_mut;
  134. //===== 单例模式写法 =====
  135. //静态创建与销毁时机测试
  136. void test_1()
  137. {
  138. cout<<"== test_1 =="<<endl;
  139. singleton_s::get()->print("<< print singleton_s >>");
  140. }
  141. //动态创建与销毁时机测试
  142. void test_2()
  143. {
  144. cout<<"== test_2 =="<<endl;
  145. singleton_d::get()->print("<< print singleton_d >>");
  146. singleton_d::get()->clear();
  147. }
  148. //===== 测试准备 =====
  149. //静态模板: 限制构造函数--真单例
  150. class vclog : public Tsingle_s<vclog>
  151. {
  152. TSINGLE(vclog,Tsingle_s)
  153. public:
  154. void print(string log)
  155. {
  156. cout<<"vclog: "<<log<<endl;
  157. }
  158. };
  159. //动态模板: 限制构造函数--真单例
  160. class dclog : public Tsingle_d<dclog>
  161. {
  162. TSINGLE(dclog,Tsingle_d)
  163. public:
  164. void print(string log)
  165. {
  166. cout<<"dclog: "<<log<<endl;
  167. }
  168. };
  169. //不限制构造函数--伪单例(可以通过构造函数创建对象)
  170. class cclog
  171. {
  172. public:
  173. void print(string log)
  174. {
  175. cout<<"cclog: "<<log<<endl;
  176. }
  177. };
  178. //===== 测试准备 =====
  179. //单例模板测试
  180. void test_3()
  181. {
  182. cout<<"== test_3 =="<<endl;
  183. //静态模板
  184. vclog::get()->print("123"); //真单例推荐用法
  185. Tsingle_s<cclog>::get()->print("456"); //伪单例推荐用法
  186. //动态模板
  187. dclog::get()->print("123qwe"); //真单例推荐用法
  188. Tsingle_s<dclog>::get()->print("456qwe"); //伪单例推荐用法
  189. }
  190. //===== 简单日志-单例 =====
  191. #define cl ""<<end
  192. #define okc ok_c && op_c && oc_c
  193. #define okf ok_f && op_f && oc_f
  194. class vlog
  195. {
  196. public:
  197. enum level{ e_error,e_warning,e_debug,e_info };
  198. static vlog* instance() { if(obj==nullptr){obj=new vlog;} return obj; };
  199. void set_level(level elc) { el_c=elc; }
  200. void set_status(bool oc) { oc_c=oc; }
  201. bool init(level el = e_info)
  202. {
  203. if(op_c) { return op_c; }
  204. el_c = el; op_c = true; return op_c;
  205. }
  206. template<class T>
  207. vlog& operator<<(const T &txt)
  208. { if(okc) std::cout<<txt; return *this; };
  209. vlog& operator<<(std::ostream& (*end)(std::ostream&))
  210. { if(okc) std::cout<<cl; return *this; };
  211. vlog& operator<<(level el)
  212. {
  213. if(el <= el_c) ok_c = true; else ok_c = false;
  214. if(okc){ std::cout<<vec[el]<<"] "; }
  215. return *this;
  216. };
  217. explicit vlog()
  218. {
  219. vec.push_back("[Err");
  220. vec.push_back("[War");
  221. vec.push_back("[Deb");
  222. vec.push_back("[Inf");
  223. }
  224. private:
  225. bool oc_c = true;
  226. bool op_c = false;
  227. bool ok_c = false;
  228. level el_c;
  229. static vlog* obj;
  230. std::vector<std::string> vec;
  231. std::string v_filename;
  232. std::string get_time()
  233. {
  234. time_t t; time(&t); char tmp[32];
  235. strftime(tmp,sizeof(tmp),"%Y-%m-%d %H:%M:%S",localtime(&t));
  236. return tmp;
  237. }
  238. class mcv { ~mcv(){delete obj; obj = nullptr;} }; static mcv t;
  239. };
  240. vlog* vlog::obj = nullptr;
  241. #define vloge(...) \
  242. (*Tsingle_s<vlog>::get())<<vlog::e_error\
  243. <<"["<<__FILE__<<":<"<<__LINE__<<">] <<<< "<<__VA_ARGS__<<endl \
  244. #define vlogw(...) \
  245. (*Tsingle_s<vlog>::get())<<vlog::e_warning\
  246. <<"["<<__FILE__<<":<"<<__LINE__<<">] <<<< "<<__VA_ARGS__<<endl \
  247. #define vlogd(...) \
  248. (*Tsingle_s<vlog>::get())<<vlog::e_debug\
  249. <<"["<<__FILE__<<":<"<<__LINE__<<">] <<<< "<<__VA_ARGS__<<endl \
  250. #define vlogf(...) \
  251. (*Tsingle_s<vlog>::get())<<vlog::e_info\
  252. <<"["<<__FILE__<<":<"<<__LINE__<<">] <<<< "<<__VA_ARGS__<<endl \
  253. //===== 简单日志-单例 =====
  254. //简单日志测试
  255. void test_4()
  256. {
  257. cout<<"== test_4 =="<<endl;
  258. Tsingle_s<vlog>::get()->init(vlog::e_debug); //设置打印等级
  259. //原生接口
  260. (*Tsingle_s<vlog>::get())<<vlog::e_info<<123<<endl;
  261. (*Tsingle_s<vlog>::get())<<vlog::e_debug<<456<<endl;
  262. (*Tsingle_s<vlog>::get())<<vlog::e_warning<<"qwe"<<endl;
  263. (*Tsingle_s<vlog>::get())<<vlog::e_error<<"asd"<<endl;
  264. //宏接口
  265. vlogf("100");
  266. vlogd("200");
  267. vlogw("300");
  268. vloge("400");
  269. }
  270. int main()
  271. {
  272. cout<<"== begin =="<<endl;
  273. //实际应用
  274. test_1();
  275. test_2();
  276. test_3();
  277. test_4();
  278. cout<<"== end =="<<endl;
  279. return 0;
  280. }
  281. /*
  282. * 1.静态创建与销毁时机测试
  283. *
  284. in exit_class
  285. in singleton_s
  286. == begin ==
  287. == test_1 ==
  288. << print txt >>
  289. == end ==
  290. out singleton_s
  291. out exit_class
  292. *
  293. * 2.动态创建与销毁时机测试
  294. *
  295. == begin ==
  296. == test_2 ==
  297. in exit_class
  298. in singleton_d
  299. << print singleton_d >>
  300. out singleton_d
  301. == end ==
  302. *
  303. * 3.模板单例模式测试
  304. *
  305. == begin ==
  306. == test_3 ==
  307. vclog: 123
  308. cclog: 456
  309. dclog: 123qwe
  310. dclog: 456qwe
  311. == end ==
  312. *
  313. * 4.简单日志模板测试
  314. *
  315. == begin ==
  316. == test_4 ==
  317. [Deb] 456
  318. [War] qwe
  319. [Err] asd
  320. [Deb] [../cpp_design/singleton.cpp:<304>] <<<< 200
  321. [War] [../cpp_design/singleton.cpp:<305>] <<<< 300
  322. [Err] [../cpp_design/singleton.cpp:<306>] <<<< 400
  323. == end ==
  324. */
  1. //!
  2. //! Tsingle.h
  3. //!
  4. #ifndef TSINGLE_H
  5. #define TSINGLE_H
  6. #include <mutex>
  7. //单例模板限制宏
  8. #define TSINGLE(class,single) \
  9. public: \
  10. friend single<class>; \
  11. class() = default; \
  12. ~class() = default; \
  13. class(const class &) = delete; \
  14. private:
  15. //静态模板
  16. template<class T>
  17. class Tsingle_s
  18. {
  19. public:
  20. static T* get(){ return _obj; }
  21. private:
  22. static T *_obj;
  23. friend T;
  24. Tsingle_s() { static exit_class exit; }
  25. ~Tsingle_s() = default;
  26. Tsingle_s(const Tsingle_s &) = delete ;
  27. struct exit_class { ~exit_class() { delete _obj; } };
  28. };
  29. //注意头文件的多重定义
  30. template<class T> T *Tsingle_s<T>::_obj = new T;
  31. //动态模板
  32. template<class T>
  33. class Tsingle_d
  34. {
  35. public:
  36. static T* get()
  37. {
  38. if(_obj == nullptr)
  39. {
  40. _mut.lock();
  41. if(_obj == nullptr)
  42. { _obj = new T; }
  43. _mut.unlock();
  44. }
  45. return _obj;
  46. }
  47. void clean()
  48. {
  49. _mut.lock();
  50. delete _obj;
  51. _obj = nullptr;
  52. _mut.unlock();
  53. }
  54. private:
  55. static T *_obj;
  56. static std::mutex _mut;
  57. friend T;
  58. Tsingle_d() = default;
  59. ~Tsingle_d() = default;
  60. Tsingle_d(const Tsingle_d &) = delete ;
  61. };
  62. //注意头文件的多重定义
  63. template<class T> T *Tsingle_d<T>::_obj = nullptr;
  64. template<class T> std::mutex Tsingle_d<T>::_mut;
  65. #endif // TSINGLE_H

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号