当前位置: 首页 > news >正文

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

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

5.1、内存泄漏的检测工具valgrind
安装
sudo apt install valgrind
使用

[外链图片转存中…(img-Onqi9PtX-1728058419413)]

5.2、单例模式自动释放的四种方法 & 多线程
1、友元类

[外链图片转存中…(img-yl7twkoI-1728058419413)]

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

#include <iostream>using std::cout;
using std::endl;class Singleton
{friend class AutoRelease;
public:static Singleton *getInstance(){if(nullptr == _pInstance){_pInstance = new Singleton();}return _pInstance;}static void destroy(){if(_pInstance){delete _pInstance;_pInstance =nullptr;}}private:Singleton(){cout << "Singleton()" << endl;}~Singleton(){cout << "~Singleton()" << endl;}
private:static Singleton *_pInstance;
};
Singleton *Singleton::_pInstance = nullptr;class AutoRelease
{
public:AutoRelease(){cout << "AutoRelease()" << endl;}~AutoRelease(){cout << "~AutoRelease()" << endl;if(Singleton::_pInstance){delete Singleton::_pInstance;Singleton::_pInstance =nullptr;}}
};
int main(int argc, char **argv)
{Singleton *ps1 = Singleton::getInstance();AutoRelease ar;//栈对象/* ps1->destroy(); */return 0;
}
2、内部类 + 静态数据成员

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

  • 若_ar定义为类成员,则会死锁:
    • new Singleton(),导致_ar在创建的单例堆对象内部,无法使其自动创建&析构(析构自身前,进行delete _pInstance
    • 应将_ar定义为static
    • [外链图片转存中…(img-8lWGqW65-1728058419414)]
#include <iostream>using std::cout;
using std::endl;// 2、内部类 + 静态数据成员class Singleton
{
public:static Singleton *getInstance(){if (_pInstance == nullptr){_pInstance = new Singleton(); // 构造函数// _ar;}return _pInstance;}static void destroy(){if (_pInstance){delete _pInstance;_pInstance = nullptr;}}private:class AutoRelease{public:AutoRelease(){cout << "AutoRelease()" << endl;}~AutoRelease(){cout << "~AutoRelease()" << endl;if (_pInstance){delete _pInstance;_pInstance = nullptr;}}};private:Singleton(){cout << "Singleton()" << endl;}~Singleton(){cout << "~Singleton()" << endl;}private:static Singleton *_pInstance; // 前向声明;定义为static,位于全局静态区(不属于本类!)static AutoRelease _ar; // 前向声明;对象数据成员, _ar不能存在堆上,否则死锁;定义为static,位于全局静态区(不属于本类!)
};Singleton *Singleton::_pInstance = nullptr; // 静态对象必须在类外进行正式声明!
Singleton::AutoRelease Singleton::_ar; // 静态对象必须在类外进行正式声明!int main(int argc, char **argv)
{Singleton *ps1 = Singleton::getInstance();/* Singleton::AutoRelease ar;//栈对象 *//* ps1->destroy(); */return 0;
}/*
AutoRelease()
Singleton()
~AutoRelease()
~Singleton()*/
采用模板
  • Singleton.h
#ifndef __WD_TEMPLATE_SINGLETON_H__
#define __WD_TEMPLATE_SINGLETON_H__#include <iostream>
using std::cout;
using std::endl;
#if 0
class Singleton
{
public:static Point *getInstance(int ix, int iy){if(nullptr == _pInstance) {_pInstance = new Point(ix, iy);_ar;//为了在模板参数推导时创建ar对象}return _pInstance;}
};
#endif
template <class T>
class Singleton
{
public:template <class... Args>static T *getInstance(Args... args){if (nullptr == _pInstance){_pInstance = new T(args...);_ar; // 为了在模板参数推导时创建ar对象}return _pInstance;}private:class AutoRelease{public:AutoRelease(){cout << "AutoRelease()" << endl;}~AutoRelease(){cout << "~AutoRelease()" << endl;if (_pInstance){delete _pInstance;_pInstance = nullptr;}}};private:Singleton(){cout << "Singleton()" << endl;/* _ar; */}~Singleton(){cout << "~Singleton()" << endl;}private:static T *_pInstance;// 前向声明;定义为static,位于全局静态区(不属于本类!)static AutoRelease _ar;// 前向声明;对象数据成员, _ar不能存在堆上,否则死锁;定义为static,位于全局静态区(不属于本类!)
};template <class T>
T *Singleton<T>::_pInstance = nullptr; // 静态对象必须在类外进行正式声明!template <class T>
typename Singleton<T>::AutoRelease Singleton<T>::_ar;  // 静态对象必须在类外进行正式声明! // typename表名是一个类型#endif
  • Test.cpp

    • #include "Singleton.h"#include <iostream>
      using std::cout;
      using std::endl;class Point
      {
      public:Point(int ix = 0, int iy = 0): _ix(ix), _iy(iy){	cout << "Point(int = 0,int = 0)" << endl;	}void print() const{cout << "(" << _ix<< "," << _iy<< ")" << endl;}~Point(){cout << "~Point()" << endl;}private:int _ix;int _iy;
      };int main()
      {Point *pt1 = Singleton<Point>::getInstance(1, 2);Point *pt2 = Singleton<Point>::getInstance(3, 4);pt1->print();pt2->print();cout << "p1 = " << pt1 << endl<< "p2 = " << pt2 << endl;return 0;
      }
3、饿汉模式 + atexit
atexit

[外链图片转存中…(img-M9pmTrsb-1728058419415)]

#include <stdlib.h>
#include <iostream>using std::cout;
using std::endl;void func()
{cout << "void func()" << endl;
}void test()
{atexit(func); // atexit: 进程正常结束时候,注册的func会被执行,注册几次就会执行几次atexit(func);atexit(func);atexit(func);atexit(func);
}int main(int argc, char **argv)
{cout << "start test..." << endl;test();cout << "finish test..." << endl;return 0;
}/*
start test...
finish test...
void func()
void func()
void func()
void func()
void func()*/
饿汉模式 + atexit

[外链图片转存中…(img-tBQqgF0g-1728058419415)]

[外链图片转存中…(img-ruQk952y-1728058419415)]

#include <stdlib.h>
#include <iostream>using std::cout;
using std::endl;// 3、atexit + 饿汉模式class Singleton
{
public:static Singleton *getInstance(){// 在多线程情况下,是不安全的if (_pInstance == nullptr){_pInstance = new Singleton(); // 构造函数atexit(destroy);              // 使用atexit:注册函数destroy一次, 当进程正常结束后,会调用一次注册的函数destroy} else {cout << "_pInstance != nullptr" << endl;}return _pInstance;}static void destroy(){if (_pInstance){delete _pInstance;_pInstance = nullptr;}}private:Singleton(){cout << "Singleton()" << endl;}~Singleton(){cout << "~Singleton()" << endl;}private:static Singleton *_pInstance;
};/* Singleton *Singleton::_pInstance = nullptr; //饱(懒)汉模式, 问题:多线程下,单例模式失效;*/
Singleton *Singleton::_pInstance = getInstance(); // 饿汉模式,可解决多线程不安全问题void *func1(void *arg)
{Singleton::getInstance();
}void *func2(void *arg)
{Singleton::getInstance();
}void *func3(void *arg)
{Singleton::getInstance();
}
int main(int argc, char **argv)
{Singleton *ps1 = Singleton::getInstance();// 饱(懒)汉模式下,多线程不安全;-- 解决:使用饿汉模式// pthread_t th1, th2, th3;// pthread_create(&th1, nullptr, func1, nullptr);// pthread_create(&th2, nullptr, func2, nullptr);// pthread_create(&th3, nullptr, func3, nullptr);return 0;
}
4、多线程场景:pthread_once + atexit

[外链图片转存中…(img-MvIJXvC9-1728058419415)]

#include <pthread.h>
#include <stdlib.h>
#include <iostream>using std::cout;
using std::endl;//4、atexit + pthread_once
//有平台问题,只能在Linux下使用class Singleton
{
public:static Singleton *getInstance(){//当第一个参数是某个固定值的时候,可以保证第一个参数只会被//调用一次  call_oncepthread_once(&_once, init);return _pInstance;}static void init(){_pInstance = new Singleton();//构造函数atexit(destroy);}static void destroy(){if(_pInstance){delete _pInstance;_pInstance = nullptr;}}private:Singleton(){cout << "Singleton()" << endl;}~Singleton(){cout << "~Singleton()" << endl;}
private:static Singleton *_pInstance;static pthread_once_t _once;
};Singleton *Singleton::_pInstance = nullptr; //饱(懒)汉模式
/* Singleton *Singleton::_pInstance = getInstance();//饿汉模式 */
pthread_once_t Singleton::_once = PTHREAD_ONCE_INIT;int main(int argc, char **argv)
{Singleton *ps1 = Singleton::getInstance();return 0;
}

http://www.mrgr.cn/news/42904.html

相关文章:

  • 《计算机原理与系统结构》学习系列——计算机的算数运算(下)
  • SynchronousQueue 的 常用场景及使用示例
  • 【AUTOSAR 基础软件】COM模块详解(通信)
  • 信息安全工程师(33)访问控制概述
  • 【越学学糊涂的Linux系统】(5)shell命令以及运行原理|权限问题
  • 【我的 PWN 学习手札】tcache stash unlink
  • NVIDIA NVLink-C2C
  • 【每天学个新注解】Day 15 Lombok注解简解(十四)—@UtilityClass、@Helper
  • LC108-将有序数组转化为二叉搜索树(二叉平衡树)
  • Pikachu-Unsafe FileUpload-客户端check
  • 《西北师范大学学报 (自然科学版)》
  • 编程基础:详解 C++ 中的 `std::sort` 函数
  • 2024年7月大众点评全国火锅前百名城市分析
  • Android 13.0 系统内存优化之修改dalvik虚拟机的内存参数
  • 网络基础知识笔记(四)
  • ExcelToWord-Excel套打Word-Word邮件合并工具分享
  • 设计模式之原型模式(通俗易懂--代码辅助理解【Java版】)
  • 入手一个小扒菜fqrr#com
  • Java-运算符
  • 迭代器