C++单例模式

单例模式是一种设计模式,它保证一个类只有一个对象。因此单例模式要私有化构造函数,禁用拷贝构造以及赋值重载。同时还要提供一个静态成员函数获取单例对象。

单例模式有两种实现方式:饿汉模式和懒汉模式

饿汉模式:创建静态单例对象,它在编译期间就被初始化,即在main函数执行之前就初始化

优点:线程安全,因为单例对象在main函数执行之前就初始化完成,不存在多线程竞争初始化单例对象的问题

缺点:占用资源,因为单例对象初始化时可能会加载许多其他资源,导致进程启动慢


懒汉模式:创建静态单例对象指针,实现延迟加载,只有在第一次请求单例对象时才初始化

优点:延迟初始化,避免加载不必要的资源

缺点:线程不安全,如果没有线程同步机制,可能会导致多个线程竞争初始化单例对象问题

1.饿汉模式

cpp 复制代码
//饿汉模式
class ConfigInfo
{
private:
	static ConfigInfo _info;//静态单例对象
	std::string _ip = "127.0.0.1";
	int _port = 8080;
private:
	//私有化构造函数
	ConfigInfo() {}
public:
	//禁用拷贝构造
	ConfigInfo(const ConfigInfo& info) = delete;
	//禁用赋值重载
	ConfigInfo& operator=(const ConfigInfo& info) = delete;
	//静态成员函数,返回单例对象指针
	static ConfigInfo* GetInstance()
	{
		return &_info;
	}
	//获取IP地址
	std::string GetIP()
	{
		return _ip;
	}
	//设置IP地址
	void SetIP(std::string ip)
	{
		_ip = ip;
	}
};
//静态单例对象的类外定义
ConfigInfo ConfigInfo::_info;
int main()
{
	ConfigInfo* info = ConfigInfo::GetInstance();
	std::cout << info->GetIP() << std::endl;
	info->SetIP("127.4.6.34");
	std::cout << info->GetIP() << std::endl;
	return 0;
}

2.懒汉模式

GetInstance函数中判断_info==nullptr会有线程安全问题:假设两个线程都成功进入了if内部,就会多次new分配资源,因此要进行加锁。加锁后又存在性能问题:

每个线程到此处都要进行加锁解锁,但实际上单例对象只有在第一次被调用时才会被判断为空并进行new资源分配,往后再被调用时一定不为nullptr。所以只要在得一次调用时进行加锁即可,这里要进行双检查加锁。

cpp 复制代码
//懒汉模式
class ConfigInfo
{
private:
	static ConfigInfo* _info;//静态单例对象
	std::string _ip = "127.0.0.1";
	int _port = 8080;
	static std::mutex _mtx;//静态锁
private:
	//私有化构造函数
	ConfigInfo() {}
public:
	//禁用拷贝构造
	ConfigInfo(const ConfigInfo& info) = delete;
	//禁用赋值重载
	ConfigInfo& operator=(const ConfigInfo& info) = delete;
	//静态成员函数,返回单例对象指针
	static ConfigInfo* GetInstance()
	{
		//此处判断_info==nullptr会有线程安全问题:假设两个线程都成功进入了if内部,就会多次new分配资源
		//因此要进行加锁
		//加锁后又存在性能问题:
		//每个线程到此处都要进行加锁解锁,但实际上单例对象只有在第一次被调用时才会被判断为空并进行new资源分配,往后再被调用时一定不为nullptr
		//所以只要在得一次调用时进行加锁即可
		//这里要进行双检查加锁
		if (_info == nullptr)
		{
			std::unique_lock<std::mutex> lock(_mtx);
			if (_info == nullptr)
			{
				_info = new ConfigInfo;
			}
		}
		return _info;
	}
	//获取IP地址
	std::string GetIP()
	{
		return _ip;
	}
	//设置IP地址
	void SetIP(std::string ip)
	{
		_ip = ip;
	}
};
//静态单例对象的类外定义
ConfigInfo* ConfigInfo::_info = nullptr;
//静态锁类外定义
std::mutex ConfigInfo::_mtx;
int main()
{
	ConfigInfo* info = ConfigInfo::GetInstance();
	std::cout << info->GetIP() << std::endl;
	info->SetIP("127.4.6.34");
	std::cout << info->GetIP() << std::endl;
	return 0;
}
相关推荐
C++ 老炮儿的技术栈4 小时前
基于Qt实现轻量化本地音乐播放器
开发语言·c++·qt·c·播放器·音乐
qq_448011164 小时前
C语言中的柔性数组
c语言·开发语言·柔性数组
小白学大数据4 小时前
长周期爬虫的数据一致性:断点续爬 + 事务回滚保障采集质量
开发语言·爬虫·测试工具
zlinear数据采集卡5 小时前
D223上位机C#开发实战:从帧解析到波形显示的完整实现
开发语言·arm开发·嵌入式硬件·fpga开发·开源·c#
Poo_Chai5 小时前
QT emit信号后完整处理流程,包括槽函数响应流程
java·开发语言·数据库
瑞码空间5 小时前
Java 图形界面(GUI)完整知识点手册
java·开发语言·图形界面·swing
小努蛋6 小时前
linux编译openresty异常问题,lua_cjson.c:706:5: 错误: ‘for‘ 循环初始化声明只在 C99 或 C++ 模式下允许
开发语言·lua·openresty
qz_Serene6 小时前
C++:类和对象(上)
开发语言·c++
西安景驰电子6 小时前
《PTP精确时间协议系列》第一篇:从原理到应用,全面解读IEEE 1588
linux·运维·服务器·开发语言·网络·windows·php
ctlover7 小时前
Python文件操作
开发语言·python