C++单例模式

1.概念

单例模式
设计模式是 被反复使用 多数人知晓 经过分类的、代码设计经验的总结

单例模式:
一个类只能创建一个对象 即单例模式,该模式可以保证系统中该类只有一个实例

单例模式分为饿汉模式和懒汉模式

饿汉模式

一开始就创建对象(main函数之前)
在这里插入图片描述
假设想要vector数组全局只有一份
所以进行限制,使之不能随意创建对象 即将构造函数私有化

若想要创建对象,则通过公有的成员函数getinstallce创建
为了保证每次获取的都是同一个对象,就定义了一个静态的类类型的指针 _p
而静态的成员变量,需要在类外面初始化
在定义静态成员变量时 创建对象。还可以通过设置锁进行多线程间的安全访问
在这里插入图片描述

代码实现

饿汉模式
class stu
{
public:
	static stu* getinstallce()
	{
		return _p;
	}
	void add(const string& str)
	{
		_mtx.lock();//加锁
		_v.push_back(str);
		++_x;
		_mtx.unlock();//解锁
	}
	void print()
	{
		_mtx.lock();//加锁
		for (auto& e : _v)
		{
			cout << e << " ";
			cout << endl;
		}
		_mtx.unlock();//解锁
	}
private:
	//限制类外不能随意创建对象
	//构造函数私有化
	stu(int x=0)
		:_x(x)
	{
	}
private:
	mutex _mtx;
	int _x=0;
	vector<string>_v;
	static stu* _p;
};
//static成员变量在类外定义
stu* stu:: _p = new stu;


int main()
{
	int n = 10;
	thread t1([n]() {
		for (int i = 0; i < n; i++)
		{
			stu::getinstallce()->add("t1线程:"+to_string(i));
		}
		});
	thread t2([n]() {
		for (int i = 0; i < n; i++)
		{
			stu::getinstallce()->add("t2线程:" + to_string(2*i));
		}
		});
	t1.join();
	t2.join();
	stu::getinstallce()->print();
}
int main()
{
	stu::getinstallce()->add("张三");
	stu::getinstallce()->add("李四");
	stu::getinstallce()->print();//打印
	return 0;
}

懒汉模式

第一次访问实例对象时创建(第一次调用getinstallce函数时创建)

在饿汉模式的代码的基础上进行改造
在这里插入图片描述
若_p指针为空,在创建对象,并返回
在调用getinstallce函数时才创建对象

虽然看似没有问题,但是在多线程下还存在线程安全的问题
所以采用双检查加锁的方式
在这里插入图片描述

具体代码

//懒汉模式
class stu
{
public:
	static stu* getinstallce()
	{
		//双检查加锁
		if (_p == nullptr)
		{
			_imtx.lock();//加锁
			if (_p == nullptr)
			{
				_p = new stu;
			}
			_imtx.unlock();//解锁
		}
		return _p;
	}
	void add(const string& str)
	{
		_mtx.lock();//加锁
		_v.push_back(str);
		++_x;
		_mtx.unlock();//解锁
	}
	void print()
	{
		_mtx.lock();//加锁
		for (auto& e : _v)
		{
			cout << e << " ";
			cout << endl;
		}
		_mtx.unlock();//解锁
	}
	//特殊情况下释放单例对象
	static void delinstance()
	{
		_imtx.lock();
		if (_p)
		{
			delete _p;
			_p = nullptr;
		}
		_imtx.unlock();
	}
private:
	//限制类外不能随意创建对象
	//构造函数私有化
	stu(int x = 0)
		:_x(x)
	{
	}
	
	//防拷贝
	stu(const stu& s) = delete;
	stu& operator=(const stu& s) = delete;

private:
	static mutex _imtx;
	mutex _mtx;
	int _x = 0;
	vector<string>_v;
	static stu* _p;
};
//static成员变量在类外定义	 
stu* stu::_p = nullptr;
//将静态锁在类外初始化
mutex stu::_imtx;



懒汉模式和饿汉模式的优缺点

饿汉模式的缺点:

1.若单例对象初始化很慢(如初始化动作多),main函数之前就要申请,暂时不需要使用 就会造成 占用资源、程序启动会变慢受影响
2.若两个单例都是饿汉,并且有依赖关系,要求单例1先创建,单例2再创建,饿汉无法控制顺序,懒汉才可以

(两者是懒汉,则都是使用 成员的静态指针进行new创建对象的,谁先new是控制不住的
而两者都是饿汉,则都是在getinstallce函数中创建对象,
可以控制单例1先在getinstallce函数中创建对象,再让单例2在getinstallce函数中创建对象)

饿汉模式的优点:

优点只有一个,简单

懒汉模式

懒汉完美的解决了上面饿汉的问题,变得相对更复杂一点

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值