c++ 单例模式介绍与实现以及单例模式的自动释放

编程入门 行业动态 更新时间:2024-10-18 23:32:33

c++ 单例<a href=https://www.elefans.com/category/jswz/34/1771241.html style=模式介绍与实现以及单例模式的自动释放"/>

c++ 单例模式介绍与实现以及单例模式的自动释放

要求:一个类只能创建一个对象

不能是栈对象

只能是堆对象,且在类内部

应用场景

只要出现全局对象的地方都可以使用单例模式

取代全局变量的位置

替换原因:全局对象不便管理

全局唯一的资源或只需要出现一个

配置文件、网页库、字典库、日志系统写的日志对象

配置文件的信息是程序的输入

优点

内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例

避免对资源的多重占用(比如写文件操作)

缺点

没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。

解决方案

将构造函数私有化

这样该类就不会被实例化


定义一个私有的静态数据成员指针,指向本类型的对象,即单例对象

私有的本类型静态数据成员指针

初始化本类型静态数据成员指针

定义一个静态的成员函数getInstance方法用于获取实例

静态成员函数无需对象也可调用

如果把函数成员声明为静态的,就可以把函数与类的任何特定对象独立开来。静态成员函数即使在类对象不存在的情况下也能被调用,静态函数只要使用类名加范围解析运算符 :: 就可以访问。

static Singleton * getInstance()
{if(_pInstance == nullptr) {_pInstance = new Singleton();}return _pInstance;
}

若本类型还未创建过对象,new一个本类型对象,若已经存在本类型对象,返回本类型对象指针

两种模式

饿汉模式

饿汉模式就是立即加载,一般情况下在调用getInstance 方法之前就已经产生了实例,也就是在类加载的时候已经产生了一个单里对象了。

饿汉模式是线程安全的

代码演示(java实现)

初始化

Singleton * Singleton::instance = new Singleton();

懒汉模式

什么时候需要这个单例对象时,再去创建实例。

代码演示(java实现)

懒汉模式的问题

if(instance == nullptr)
{instance = new Singleton();
}

这两行代码既包含了读操作,也包含了修改操作,这两行代码是两个不走,不是原子性的。此代码存在线程安全问题

改进方案:在多线程下运行时,需要进行加锁操作(最终实现)

class Singleton {
public:static Singleton * getInstance(){if(instance == nullptr) {pthread_mutex_lock(&mutex);//需要在数据成员内加入mutexif(instance == nullptr) {instance = new Singleton();} pthread_mutex_unlock(&mutex);}return instance;}static void destroy(){if(_pInstance) {//在类内部执行delete表达式delete _pInstance;}}
private:Singleton();~Singleton();static pthread_mutex_t mutex;static Singleton * instance;
};

初始化

Singleton * Singleton::instance = nullptr;

单例模式的自动释放

必要性

程序需要检查是否存在内存泄漏,如果单例对象没有进行内存回收,那么检测工具会认为发生了内存泄漏,会干扰程序员判断是否发生内存泄漏

检测内存泄漏的工具valgrind

使用方式

valgrind --tool=memcheck --leak-check=fukk ./test(可执行文件)
valgrind --tool=massif --stack=yes ./client
使友元模式进行设计

单例对象声明与实现

class AutoRelease; //前向声明class Singleton
{friend AutoRelease;
public:static Singleton * getInstance();
private:Singleton();~Singleton();
private:static Singleton * _pInstance;
};SIngleton * Singleton::getInstance()
{if(nullptr == _pInstace){_pInstance = new Singleton;}return _pInstance;
}

自动释放类声明与实现

class AutoRelease
{
public:AutoRelease(){cout << "AutoRelease()" << endl;}~AutoRelease(){cout << "~AutoRelease()" << endl;if(Singleton::_pInstance){delete Singleton::_pInstance;Singleton:_pInstance = nullptr;}}
};

可自动释放的单例对象实现

//静态成员初始化
Singleton * Singleton::_pInstance = nullptr;void test0()
{Singleton *p1 = Singleton::getInstance();//自动释放实现需要声明一个AutoRelease类AutoRelease p2;
}
内部类加静态数据成员形式

单例对象的声明

//单例对象自动释放的实现方式之一: 嵌套类+静态对象
class Singleton
{
public:static Singleton * getInstance(){if(nullptr == _pInstance)_pInstance == new Singleton();return _pInstance;}
private:class AutoRelease{public:~AutoRelease(){cout << "~AutoRelease()" << endl;if(_pInstance)delete _pInstance;  //内部类可以直接使用外部类的数据成员}};
private:Singleton() {  cout << "Singleton()" << endl;  }~Singleton() {  cout << "~Singleton()" << endl;}static SIngleton * _pInstance;static AutoRelease _ar;  //_ar是静态对象,位于静态存储区//当程序退出main函数时会自动回收//分配给单例对象的内存int _ix;
};

ar时AutoRelease类静态对象,位于全局静态区, pInstance是外部Singleton类静态对象指针,也位于全局静态区

因此当程序退出main函数时,会delete _at的同时会调用析构函数

从而可以自动回收分配给_pInstance 的内存空间

静态成员的初始化

Singleton * Singleton::_pInstance = nullptr;
Singleton::AutoRelease Singleton::_ar;

类调用

int main()
{Singleton * p1 = Singleton::getInstance();Singleton * p2 = SIngleton::getInstance();cout << "p1 = " << p1 << endl;cout << "p2 = " << p2 << endl;return 0;
}
atexit方式进行

atexit函数

函数说明

用来注册指向exit() 函数前执行的终止处理程序

当程序通过调用exit()或从main中返回时被调用。终止处理程序执行的顺序和注册时的顺序时相反的,终止处理程序没有参数传递。同一个函数若注册多次,那它也会被调用多次。

当一个子进程时通过调用fork函数产生时,它将继承父进程的所有终止处理程序。在成功调用exec系列函数后,所有的终止处理程序都会被删除

函数原型

#include <stdlib.h>
int atexit(void (*function)(void));

参数列表

function

即所要注册的终止处理函数指针

使用实例

#include <iostream>using std::cout;
using std::endl;class Singleton
{
public:static Singleton * getInstance(){//对于多线程环境,不安全if(nullptr == _pInstance){_pInstance = new Singleton();atexit(destroy); }return _pInstance;}static void destroy(){if(_pInstance){delete _pInstance; //1、调用析构函数 2、operator delele_pInstance = nullptr;}}
private:Singleton(){cout << "Singleton()" << endl;}~Singleton(){cout << "~Singleton()" << endl;}
private:static Singleton * _pInstance;
};/* Singleton *Singleton::_pInstance = nullptr; //饱汉模式(懒汉模式)*/
Singleton * Singleton::_pInstance = getInstance(); //饿汉模式
pthread_once形式

pthread_once 函数

函数说明

在多线程环境中,有些事仅需要执行一次。通常当初始化应用程序时,可以比较容易地将其放在main函数中。但当你写一个库时,就不能在main里面初始化了,你可以用静态初始化,但使用一次初始化(pthread_once)会比较容易些

函数功能

本函数使用初值为PTHREAD_ONCE_INIT的once_control变量保证init_routine()函数在本进程执行序列中仅执行一次

函数原型

int pthread_once(pthread_once_t * once_control,void(*init_routine)(void));

参数列表

once_control

表示是否执行过,必须初始化为PTHREad_ONCE_INIT

init_routine

初始化函数

使用实例

#include <iostream>using std::cout;
using std::endl;class Singleton
{
public:static Singleton * getInstance();static void init();static void destroy();
private:Singleton(){cout << "Singleton()" << endl;}~Singleton(){cout << "~Singlenton()" << endl;}
private:static Singleton * _pInstance;static pthread_once_t _once;
};
Singleton * Singleton::getInstance() {pthread_once(&_once, init);return _pInstance;
}
void Singleton::init()
{_pInstance = new Singleton();atexit(destroy);
}
void Singleton::destroy()
{if(_pInstance){delete _pInstance;_pInstance = nullptr;}
}
Singleton * Singleton::_pInstance = nullptr; //饱汉模式
// Singleton * Singleton::_pInstance = Singleton::getInstance();//饿汉模式
pthread_once_t Singleton::_once = PTHREAD_ONCE_INIT;

更多推荐

c++ 单例模式介绍与实现以及单例模式的自动释放

本文发布于:2024-02-26 22:03:10,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1704101.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:模式

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!