经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C++ » 查看文章
C++使用智能指针实现模板形式的单例类
来源:jb51  时间:2021/6/15 9:23:30  对本文有异议

本文通过实例为大家分享了C++使用智能指针实现模板形式的单例类的具体代码,供大家参考,具体内容如下

实现一个模板形式的单例类,对于任意类型的类经过Singleton的处理之后,都能获取一个单例对象,并且可以传递任意参数

并且还使用了智能指针,把生成的单例对象托管给智能指针,从而实现自动回收单例对象的资源

此外,如果需要一个放在静态成员区的对象供其他类使用,又不希望修改原有的类的代码,这时候可以通过该模板套一层壳,形成单例对象。

头文件

template_singleton.hpp

  1. #include <iostream>
  2. #include <string>
  3. #include <memory>
  4.  
  5. using std::cout;
  6. using std::endl;
  7. using std::string;
  8. using std::shared_ptr;
  9. using std::make_shared;
  10.  
  11. template <typename T> class Singleton;
  12.  
  13. class Point
  14. {
  15. //由于构造和析构被设为私有,想使用单例模板创造对象,就应该把其设为友元
  16. template <typename T> friend class Singleton;
  17. public:
  18. //把析构函数设为private之后,智能指针销毁时无法调用
  19. //所以析构应该设置为public,但是就算是共有的析构,由于是把单例对象的内容托管给了智能指针
  20. //通过智能指针显式的调用析构函数,也是无法回收单例对象的,所以,不影响单例模式的实现
  21. ~Point(){
  22. cout << "~Point()" << endl;
  23. }
  24.  
  25. void show(){
  26. cout << "(" << _ix << ", " << _iy << ")" << endl;
  27. }
  28.  
  29. private:
  30. //单例模式,要把构造函数和析构函数设为私有
  31. Point(int x, int y) : _ix(x), _iy(y)
  32. {
  33. cout << "Point(int, int)" << endl;
  34. }
  35. /* ~Point(){ */
  36. /* cout << "~Point()" << endl; */
  37. /* } */
  38.  
  39. private:
  40. int _ix;
  41. int _iy;
  42. };
  43.  
  44. class Computer
  45. {
  46. //由于构造和析构被设为私有,想使用单例模板创造对象,就应该把其设为友元
  47. template <typename T> friend class Singleton;
  48.  
  49. public:
  50. void show(){
  51. cout << "name: " << _name << " price: " << _price << endl;
  52. }
  53. void reset(const string &newname, const int &newprice){
  54. _name = newname;
  55. _price = newprice;
  56. }
  57. //使用public的析构函数,不影响单例模式的实现
  58. ~Computer(){
  59. cout << "~Computer()" << endl;
  60. }
  61.  
  62. private:
  63. //单例模式,要把构造函数设为私有
  64. //使用模板生成单例对象的时候调用了make_shared函数,如果传入的是栈上的内容
  65. //make_shared函数会调用拷贝构造函数在堆上重新生成一个托管给智能指针的对象,
  66. //并把原先的对象销毁,所以会在make_shared里面执行一次析构函数
  67. /* Computer(const Computer &rhs){ */
  68. /* cout << "拷贝构造函数" << endl; */
  69. /* } */
  70. Computer(const string &name, const int price)
  71. :_name(name), _price(price)
  72. {
  73. cout << "Computer(const string &, const int &)" << endl;
  74. }
  75. /* ~Computer(){ */
  76. /* cout << "~Computer()" << endl; */
  77. /* } */
  78.  
  79. private:
  80. string _name;
  81. int _price;
  82. };
  83.  
  84. //模板形式的单例类(使用了智能指针),应该使用饱汉模式
  85. template <typename T>
  86. class Singleton
  87. {
  88. public:
  89. template <typename ...Args>
  90. static shared_ptr<T> getInstance(Args... args){
  91. if(_pInstance == nullptr){
  92. //这里会直接调用相应的类型的构造函数,托管给智能指针,类型在实例化后确定
  93. /* //使用临时对象托管给智能指针的时候,由于临时对象分配在栈上, */
  94. /* //所以在make_shared内部会重新分配堆上的空间来保存其内容, */
  95. /* //会调用拷贝构造函数,并把临时对象销毁 */
  96. /* _pInstance = make_shared<T>(T(args...)); */
  97.  
  98. //如果把一个分配在堆上的指针托管给智能指针,传入的指针就不会被销毁
  99. T *tmp = new T(args...);
  100. _pInstance = make_shared<T>(*tmp);
  101. }
  102. return _pInstance;
  103. }
  104.  
  105. private:
  106. //由于使用了模板,所以_pInstance实际上指向的是 T ,而非本类型,
  107. //所以并不会生成Singleton对象,而是直接生成相应的T对象
  108. //T在实例化之后才会确定,究竟是哪种类型,
  109. //所以Singleton的构造函数和析构函数并不会执行
  110. Singleton(){
  111. cout << "Singleton()" << endl;
  112. }
  113.  
  114. ~Singleton(){
  115. cout << "~Singleton()" << endl;
  116. }
  117.  
  118. static shared_ptr<T> _pInstance; //单例模式的指针,指向唯一的实体
  119. };
  120.  
  121. //由于类型在实例化是才会确定,所以使用饱汉模式
  122. template <typename T>
  123. shared_ptr<T> Singleton<T>::_pInstance = nullptr;

测试文件

test_template_singleton.cc

  1. #include "template_singleton.hpp"
  2. #include <stdio.h>
  3.  
  4. using std::cout;
  5. using std::endl;
  6. using std::cin;
  7.  
  8. void test(){
  9. shared_ptr<Computer> pc1 = Singleton<Computer>::getInstance("Xiaomi", 6666);
  10. cout << "pc1: ";
  11. pc1->show();
  12.  
  13. shared_ptr<Computer> pc2 = Singleton<Computer>::getInstance("Xiaomi", 6666);
  14. cout << "pc1: ";
  15. pc1->show();
  16. cout << "pc2: ";
  17. pc2->show();
  18.  
  19. pc2->reset("Huawei", 8888);
  20. cout << endl << "after pc2->reset()" << endl;
  21. cout << "pc1: ";
  22. pc1->show();
  23. cout << "pc2: ";
  24. pc2->show();
  25. cout << endl;
  26.  
  27. shared_ptr<Point> pt3 = Singleton<Point>::getInstance(1, 2);
  28. shared_ptr<Point> pt4 = Singleton<Point>::getInstance(1, 2);
  29.  
  30. cout << endl << "通过模板,可以生成不同类型的单例对象:" << endl;
  31. cout << "pt3: ";
  32. pt3->show();
  33. cout << "pt4: ";
  34. pt4->show();
  35.  
  36. cout << endl << "使用了智能指针,不同对象指向的地址也一样:" << endl;
  37. printf("&pc1 = %p\n", &pc1);
  38. printf("&pc2 = %p\n", &pc2);
  39. printf("&pt3 = %p\n", &pt3);
  40. printf("&pt4 = %p\n\n", &pt4);
  41. printf("&(*pc1) = %p\n", &(*pc1));
  42. printf("&(*pc2) = %p\n", &(*pc2));
  43. printf("&(*pt3) = %p\n", &(*pt3));
  44. printf("&(*pt4) = %p\n\n", &(*pt4));
  45.  
  46. }
  47.  
  48. int main()
  49. {
  50. test();
  51. return 0;
  52. }

运行结果

  1. Computer(const string &, const int &)
  2. pc1: name: Xiaomi price: 6666
  3. pc1: name: Xiaomi price: 6666
  4. pc2: name: Xiaomi price: 6666
  5.  
  6. after pc2->reset()
  7. pc1: name: Huawei price: 8888
  8. pc2: name: Huawei price: 8888
  9.  
  10. Point(int, int)
  11.  
  12. # 通过模板,可以生成不同类型的单例对象:
  13. pt3: (1, 2)
  14. pt4: (1, 2)
  15.  
  16. # 使用了智能指针,不同对象指向的地址也一样:
  17. &pc1 = 0x7ffe83bbd390
  18. &pc2 = 0x7ffe83bbd3a0
  19. &pt3 = 0x7ffe83bbd3b0
  20. &pt4 = 0x7ffe83bbd3c0
  21.  
  22. &(*pc1) = 0x55b750c7e300
  23. &(*pc2) = 0x55b750c7e300
  24. &(*pt3) = 0x55b750c7e360
  25. &(*pt4) = 0x55b750c7e360
  26.  
  27. ~Point()
  28. ~Computer()

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持w3xue。

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号