IT评测·应用市场-qidao123.com技术社区
标题:
valgrind & 单例模式的自动释放(多线程)
[打印本页]
作者:
河曲智叟
时间:
2024-10-9 04:13
标题:
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_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;
}
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
欢迎光临 IT评测·应用市场-qidao123.com技术社区 (https://dis.qidao123.com/)
Powered by Discuz! X3.4