欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 旅游 > 【C++】单例模式

【C++】单例模式

2024/10/24 16:40:18 来源:https://blog.csdn.net/c565114/article/details/143175892  浏览:    关键词:【C++】单例模式

1.什么是单例模式

单例模式:顾名思义,这个对象是全局的,且只有唯一的一个实例(不能创建出两份)。

用途:多个线程同时访问一个全局资源时可能会用到。例如,在C++的内存管理中,内存池只有一份,但是会有多个线程访问内存池,那么内存池的设计就可能需要单例模式。所以单例模式还是比较重要的。

2.单例模式核心设计方式

2.1饿汉模式

举例:

#include <iostream>
#include <string>
using std::cout;
using std::endl;
//配置信息类
//饿汉模式:一开始(在main函数前)就创建对象
class ConfigInfo {
public:static ConfigInfo* GetInstance() {return &_sInfo;}std::string GetIp() {return _ip;}void SetIp(const std::string& ip) {_ip = ip;}
private:ConfigInfo(){}ConfigInfo(const ConfigInfo&) = delete;ConfigInfo& operator=(const ConfigInfo&) = delete;
private:std::string _ip = "127.0.0.1";int _port = 80;//声明static ConfigInfo _sInfo;
};//定义
ConfigInfo ConfigInfo::_sInfo;int main() {cout << ConfigInfo::GetInstance() << endl;cout << ConfigInfo::GetInstance() << endl;ConfigInfo::GetInstance()->SetIp("192.33.3.22");cout << ConfigInfo::GetInstance()->GetIp() << endl;return 0;
}

饿汉模式:核心设计

1.首先把配置信息类的构造,拷贝构造,赋值重载全部设置为私有,这样就不能在类外面创建对象。

2.在私有成员中,声明一个静态的类对象,然后在类外面定义,(相当于成员函数的声明和定义分离,能够访问到私有的构造函数)这样就可以保证在全局只有唯一一个实例化的对象。(静态的成员变量不属于类,它只受类域的限制,它实际上是定义在静态区的。如果把static关键字去掉,就会“无限套娃”,是错误的做法)。

3.给一个公有的静态函数:GetInstance(),这样可以通过该函数得到对象的地址或引用从而进行更多的操作。因为是静态的,所以可以通过类名访问,更方便。

饿汉模式的问题:

问题1:

如果很多单例类都是饿汉模式,有些单例对象初始化资源很多,导致程序启动慢。迟迟进不了main函数。

问题2:

如果两个单例类有初始化依赖关系,饿汉模式也无法解决。

比如A类和B类是单例,A单例要链接数据库,B单例要用A单例访问数据库。但是A和B谁先初始化不知道,这时就有问题。

2.2懒汉模式(C++11之后)

#include <iostream>
#include <string>
using std::cout;
using std::endl;
//配置信息类
//懒汉模式:在调用时创建对象
class ConfigInfo {
public:static ConfigInfo* GetInstance() {//局部静态单例对象static ConfigInfo info;return &info;}std::string GetIp() {return _ip;}void SetIp(const std::string& ip) {_ip = ip;}
private:ConfigInfo(){cout << "ConfigInfo" << endl;}ConfigInfo(const ConfigInfo&) = delete;ConfigInfo& operator=(const ConfigInfo&) = delete;
private:std::string _ip = "127.0.0.1";int _port = 80;};int main() {cout << ConfigInfo::GetInstance() << endl;cout << ConfigInfo::GetInstance() << endl;ConfigInfo::GetInstance()->SetIp("192.33.3.22");cout << ConfigInfo::GetInstance()->GetIp() << endl;return 0;
}

与饿汉模式相比,懒汉模式就是把静态私有成员改成了GetInstance()中的静态局部对象,这样该对象在调用时只会构造一次。这样就很好的解决了饿汉模式的问题。

但这样写也有一个小问题,就是在C++11之前无法保证GetInstance()是线程安全的,也就是说当两个线程同时调用该函数时,可能会构造两次。但在C++11之后,编译器经过特殊处理了,就没问题了。如果你的编译器不支持C++11就不能用这种写法。

2.3懒汉模式(C++11之前)

#include <iostream>
#include <string>
#include <mutex>
using std::cout;
using std::endl;
//配置信息类
//懒汉模式:在调用时创建对象
class ConfigInfo {
public:static ConfigInfo* GetInstance() {//多线程调用需要考虑线程安全问题//双检查机制if (_spInfo == nullptr) {  //提高性能std::unique_lock<std::mutex> lock(_mtx);if (_spInfo == nullptr) {  //线程安全_spInfo = new ConfigInfo;}}return _spInfo;}std::string GetIp() {return _ip;}void SetIp(const std::string& ip) {_ip = ip;}
private:ConfigInfo(){cout << "ConfigInfo" << endl;}ConfigInfo(const ConfigInfo&) = delete;ConfigInfo& operator=(const ConfigInfo&) = delete;
private:std::string _ip = "127.0.0.1";int _port = 80;static ConfigInfo* _spInfo;static std::mutex _mtx;
};
ConfigInfo* ConfigInfo::_spInfo = nullptr;
std::mutex ConfigInfo::_mtx;int main() {cout << ConfigInfo::GetInstance() << endl;cout << ConfigInfo::GetInstance() << endl;ConfigInfo::GetInstance()->SetIp("192.33.3.22");cout << ConfigInfo::GetInstance()->GetIp() << endl;return 0;
}

如果你的编译器支持C++11,就可以不考虑这种写法,因为这种写法更复杂:

声明静态的对象指针和静态的锁并初始化,因为初始化一个指针的开销可以忽略不计。然后在GetInstance()函数中采用双检查机制,第一次检查是为了提高性能,避免每次调用该函数时都会上锁。第二次检查是为了保证线程安全,确保只创建一个对象。

关于内存泄漏问题:

因为new出来的对象往往要考虑释放的问题,但是单例模式有所不同。单例模式的目的就是确保全局只有唯一的一个对象,以后就算不用了没有释放也影响不大(只有一个对象,占用内存基本可以忽略,等进程结束后会自动回收)。如果真的有特殊需求,可以查阅相关资料来释放该对象(因为不建议这么做,本文就不介绍了)。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com