valgrind & 单例模式的自动释放(多线程)

打印 上一主题 下一主题

主题 1821|帖子 1821|积分 5463

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
单例模式,其中对象是由_pInstance指针来保存的,而在利用单例设计模式的过程中,也难免会碰到内存泄漏的题目。那么是否有一个方法,可以让对象自动释放,而不需要程序员自己手动去释放呢? ——嵌套类
5.1、内存泄漏的检测工具valgrind

安装

  1. sudo apt install valgrind
复制代码
利用

[外链图片转存中…(img-Onqi9PtX-1728058419413)]
5.2、单例模式自动释放的四种方法 & 多线程

1、友元类

[外链图片转存中…(img-yl7twkoI-1728058419413)]
[外链图片转存中…(img-epIiJsLR-1728058419414)]
  1. #include <iostream>
  2. using std::cout;
  3. using std::endl;
  4. class Singleton
  5. {
  6.     friend class AutoRelease;
  7. public:
  8.     static Singleton *getInstance()
  9.     {
  10.         if(nullptr == _pInstance)
  11.         {
  12.             _pInstance = new Singleton();
  13.         }
  14.         return _pInstance;
  15.     }
  16.     static void destroy()
  17.     {
  18.         if(_pInstance)
  19.         {
  20.             delete _pInstance;
  21.             _pInstance =nullptr;
  22.         }
  23.     }
  24. private:
  25.     Singleton()
  26.     {
  27.         cout << "Singleton()" << endl;
  28.     }
  29.     ~Singleton()
  30.     {
  31.         cout << "~Singleton()" << endl;
  32.     }
  33. private:
  34.     static Singleton *_pInstance;
  35. };
  36. Singleton *Singleton::_pInstance = nullptr;
  37. class AutoRelease
  38. {
  39. public:
  40.     AutoRelease()
  41.     {
  42.         cout << "AutoRelease()" << endl;
  43.     }
  44.     ~AutoRelease()
  45.     {
  46.         cout << "~AutoRelease()" << endl;
  47.         if(Singleton::_pInstance)
  48.         {
  49.             delete Singleton::_pInstance;
  50.             Singleton::_pInstance =nullptr;
  51.         }
  52.     }
  53. };
  54. int main(int argc, char **argv)
  55. {
  56.     Singleton *ps1 = Singleton::getInstance();
  57.     AutoRelease ar;//栈对象
  58.     /* ps1->destroy(); */
  59.     return 0;
  60. }
复制代码
2、内部类 + 静态数据成员

[外链图片转存中…(img-oCRKHufV-1728058419414)]


  • 若_ar界说为类成员,则会死锁:

    • new Singleton(),导致_ar在创建的单例堆对象内部,无法使其自动创建&析构(析构自身前,进行delete _pInstance)
    • 应将_ar界说为static
    • [外链图片转存中…(img-8lWGqW65-1728058419414)]

  1. #include <iostream>
  2. using std::cout;
  3. using std::endl;
  4. // 2、内部类 + 静态数据成员
  5. class Singleton
  6. {
  7. public:
  8.     static Singleton *getInstance()
  9.     {
  10.         if (_pInstance == nullptr)
  11.         {
  12.             _pInstance = new Singleton(); // 构造函数
  13.             // _ar;
  14.         }
  15.         return _pInstance;
  16.     }
  17.     static void destroy()
  18.     {
  19.         if (_pInstance)
  20.         {
  21.             delete _pInstance;
  22.             _pInstance = nullptr;
  23.         }
  24.     }
  25. private:
  26.     class AutoRelease
  27.     {
  28.     public:
  29.         AutoRelease()
  30.         {
  31.             cout << "AutoRelease()" << endl;
  32.         }
  33.         ~AutoRelease()
  34.         {
  35.             cout << "~AutoRelease()" << endl;
  36.             if (_pInstance)
  37.             {
  38.                 delete _pInstance;
  39.                 _pInstance = nullptr;
  40.             }
  41.         }
  42.     };
  43. private:
  44.     Singleton()
  45.     {
  46.         cout << "Singleton()" << endl;
  47.     }
  48.     ~Singleton()
  49.     {
  50.         cout << "~Singleton()" << endl;
  51.     }
  52. private:
  53.     static Singleton *_pInstance; // 前向声明;定义为static,位于全局静态区(不属于本类!)
  54.     static AutoRelease _ar; // 前向声明;对象数据成员, _ar不能存在堆上,否则死锁;定义为static,位于全局静态区(不属于本类!)
  55. };
  56. Singleton *Singleton::_pInstance = nullptr; // 静态对象必须在类外进行正式声明!
  57. Singleton::AutoRelease Singleton::_ar; // 静态对象必须在类外进行正式声明!
  58. int main(int argc, char **argv)
  59. {
  60.     Singleton *ps1 = Singleton::getInstance();
  61.     /* Singleton::AutoRelease ar;//栈对象 */
  62.     /* ps1->destroy(); */
  63.     return 0;
  64. }
  65. /*
  66. AutoRelease()
  67. Singleton()
  68. ~AutoRelease()
  69. ~Singleton()
  70. */
复制代码
采用模板



  • Singleton.h
  1. #ifndef __WD_TEMPLATE_SINGLETON_H__
  2. #define __WD_TEMPLATE_SINGLETON_H__
  3. #include <iostream>
  4. using std::cout;
  5. using std::endl;
  6. #if 0
  7. class Singleton
  8. {
  9. public:
  10.     static Point *getInstance(int ix, int iy)
  11.     {
  12.                 if(nullptr == _pInstance)
  13.         {
  14.                         _pInstance = new Point(ix, iy);
  15.                         _ar;//为了在模板参数推导时创建ar对象
  16.                 }
  17.                 return _pInstance;
  18.     }
  19. };
  20. #endif
  21. template <class T>
  22. class Singleton
  23. {
  24. public:
  25.         template <class... Args>
  26.         static T *getInstance(Args... args)
  27.         {
  28.                 if (nullptr == _pInstance)
  29.                 {
  30.                         _pInstance = new T(args...);
  31.                         _ar; // 为了在模板参数推导时创建ar对象
  32.                 }
  33.                 return _pInstance;
  34.         }
  35. private:
  36.         class AutoRelease
  37.         {
  38.         public:
  39.                 AutoRelease()
  40.                 {
  41.                         cout << "AutoRelease()" << endl;
  42.                 }
  43.                 ~AutoRelease()
  44.                 {
  45.                         cout << "~AutoRelease()" << endl;
  46.                         if (_pInstance)
  47.                         {
  48.                                 delete _pInstance;
  49.                                 _pInstance = nullptr;
  50.                         }
  51.                 }
  52.         };
  53. private:
  54.         Singleton()
  55.         {
  56.                 cout << "Singleton()" << endl;
  57.                 /* _ar; */
  58.         }
  59.         ~Singleton()
  60.         {
  61.                 cout << "~Singleton()" << endl;
  62.         }
  63. private:
  64.         static T *_pInstance;// 前向声明;定义为static,位于全局静态区(不属于本类!)
  65.         static AutoRelease _ar;// 前向声明;对象数据成员, _ar不能存在堆上,否则死锁;定义为static,位于全局静态区(不属于本类!)
  66. };
  67. template <class T>
  68. T *Singleton<T>::_pInstance = nullptr; // 静态对象必须在类外进行正式声明!
  69. template <class T>
  70. typename Singleton<T>::AutoRelease Singleton<T>::_ar;  // 静态对象必须在类外进行正式声明! // typename表名是一个类型
  71. #endif
复制代码


  • Test.cpp

      1. #include "Singleton.h"
      2. #include <iostream>
      3. using std::cout;
      4. using std::endl;
      5. class Point
      6. {
      7. public:
      8.         Point(int ix = 0, int iy = 0)
      9.         : _ix(ix)
      10.         , _iy(iy)
      11.         {       
      12.         cout << "Point(int = 0,int = 0)" << endl;       
      13.     }
      14.         void print() const
      15.         {
      16.                 cout << "(" << _ix
      17.                          << "," << _iy
      18.                          << ")" << endl;
      19.         }
      20.         ~Point()
      21.         {
      22.                 cout << "~Point()" << endl;
      23.         }
      24. private:
      25.         int _ix;
      26.         int _iy;
      27. };
      28. int main()
      29. {
      30.         Point *pt1 = Singleton<Point>::getInstance(1, 2);
      31.         Point *pt2 = Singleton<Point>::getInstance(3, 4);
      32.         pt1->print();
      33.         pt2->print();
      34.         cout << "p1 = " << pt1 << endl
      35.                  << "p2 = " << pt2 << endl;
      36.         return 0;
      37. }
      复制代码

3、饿汉模式 + atexit

atexit

[外链图片转存中…(img-M9pmTrsb-1728058419415)]
  1. #include <stdlib.h>
  2. #include <iostream>
  3. using std::cout;
  4. using std::endl;
  5. void func()
  6. {
  7.     cout << "void func()" << endl;
  8. }
  9. void test()
  10. {
  11.     atexit(func); // atexit: 进程正常结束时候,注册的func会被执行,注册几次就会执行几次
  12.     atexit(func);
  13.     atexit(func);
  14.     atexit(func);
  15.     atexit(func);
  16. }
  17. int main(int argc, char **argv)
  18. {
  19.     cout << "start test..." << endl;
  20.     test();
  21.     cout << "finish test..." << endl;
  22.     return 0;
  23. }
  24. /*
  25. start test...
  26. finish test...
  27. void func()
  28. void func()
  29. void func()
  30. void func()
  31. void func()
  32. */
复制代码
饿汉模式 + atexit

[外链图片转存中…(img-tBQqgF0g-1728058419415)]
[外链图片转存中…(img-ruQk952y-1728058419415)]
  1. #include <stdlib.h>
  2. #include <iostream>
  3. using std::cout;
  4. using std::endl;
  5. // 3、atexit + 饿汉模式
  6. class Singleton
  7. {
  8. public:
  9.     static Singleton *getInstance()
  10.     {
  11.         // 在多线程情况下,是不安全的
  12.         if (_pInstance == nullptr)
  13.         {
  14.             _pInstance = new Singleton(); // 构造函数
  15.             atexit(destroy);              // 使用atexit:注册函数destroy一次, 当进程正常结束后,会调用一次注册的函数destroy
  16.         } else {
  17.             cout << "_pInstance != nullptr" << endl;
  18.         }
  19.         return _pInstance;
  20.     }
  21.     static void destroy()
  22.     {
  23.         if (_pInstance)
  24.         {
  25.             delete _pInstance;
  26.             _pInstance = nullptr;
  27.         }
  28.     }
  29. private:
  30.     Singleton()
  31.     {
  32.         cout << "Singleton()" << endl;
  33.     }
  34.     ~Singleton()
  35.     {
  36.         cout << "~Singleton()" << endl;
  37.     }
  38. private:
  39.     static Singleton *_pInstance;
  40. };
  41. /* Singleton *Singleton::_pInstance = nullptr; //饱(懒)汉模式, 问题:多线程下,单例模式失效;*/
  42. Singleton *Singleton::_pInstance = getInstance(); // 饿汉模式,可解决多线程不安全问题
  43. void *func1(void *arg)
  44. {
  45.     Singleton::getInstance();
  46. }
  47. void *func2(void *arg)
  48. {
  49.     Singleton::getInstance();
  50. }
  51. void *func3(void *arg)
  52. {
  53.     Singleton::getInstance();
  54. }
  55. int main(int argc, char **argv)
  56. {
  57.     Singleton *ps1 = Singleton::getInstance();
  58.     // 饱(懒)汉模式下,多线程不安全;-- 解决:使用饿汉模式
  59.     // pthread_t th1, th2, th3;
  60.     // pthread_create(&th1, nullptr, func1, nullptr);
  61.     // pthread_create(&th2, nullptr, func2, nullptr);
  62.     // pthread_create(&th3, nullptr, func3, nullptr);
  63.     return 0;
  64. }
复制代码
4、多线程场景:pthread_once + atexit

[外链图片转存中…(img-MvIJXvC9-1728058419415)]
  1. #include <pthread.h>
  2. #include <stdlib.h>
  3. #include <iostream>
  4. using std::cout;
  5. using std::endl;
  6. //4、atexit + pthread_once
  7. //有平台问题,只能在Linux下使用
  8. class Singleton
  9. {
  10. public:
  11.     static Singleton *getInstance()
  12.     {
  13.         //当第一个参数是某个固定值的时候,可以保证第一个参数只会被
  14.         //调用一次  call_once
  15.         pthread_once(&_once, init);
  16.         return _pInstance;
  17.     }
  18.     static void init()
  19.     {
  20.         _pInstance = new Singleton();//构造函数
  21.         atexit(destroy);
  22.     }
  23.     static void destroy()
  24.     {
  25.         if(_pInstance)
  26.         {
  27.             delete _pInstance;
  28.             _pInstance = nullptr;
  29.         }
  30.     }
  31. private:
  32.     Singleton()
  33.     {
  34.         cout << "Singleton()" << endl;
  35.     }
  36.     ~Singleton()
  37.     {
  38.         cout << "~Singleton()" << endl;
  39.     }
  40. private:
  41.     static Singleton *_pInstance;
  42.     static pthread_once_t _once;
  43. };
  44. Singleton *Singleton::_pInstance = nullptr; //饱(懒)汉模式
  45. /* Singleton *Singleton::_pInstance = getInstance();//饿汉模式 */
  46. pthread_once_t Singleton::_once = PTHREAD_ONCE_INIT;
  47. int main(int argc, char **argv)
  48. {
  49.     Singleton *ps1 = Singleton::getInstance();
  50.     return 0;
  51. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

河曲智叟

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表