单例模式,其中对象是由_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)]
- new Singleton(),导致_ar在创建的单例堆对象内部,无法使其自动创建&析构(析构自身前,进行
#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_once
pthread_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;
}