C++特殊类设计1 单例模式

文章目录


 一个类只能创建一个对象,即单例模式,该模式可以保证系统中该类只有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。单例模式有两种实现模式:饱汉,饿汉

1、饿汉

 饿汉模式就是说不管你将来用不用,程序启动时就创建一个唯一的实例对象。
 思路:简单来说,就是将类的构造函数,拷贝构造函数,赋值运算符重载私有,随后定义一个静态的类对象,再给出一个静态的类对象的获取方法。

class Singleton
{
public:
	static Singleton* GetInstance()
	{
		return &m_instance;
	}
private:
	// 构造函数私有
	Singleton()
	{
		cout<<"Create Singleton Obj."<<endl;
	}
	// C++98 防拷贝
	Singleton(Singleton const&);
	Singleton& operator=(Singleton const&);
	static Singleton m_instance;
};
Singleton Singleton::m_instance;
//饿汉模式
void main()
{
	Singleton *ps = Singleton::GetInstance();
	Singleton *ps1 = Singleton::GetInstance();
	Singleton *ps2 = Singleton::GetInstance();
	system("pause");
}

 饿汉模式优点:简单。 但由于只要程序启动,就会初始化类对象,比较耗资源,非线程安全。

2、饱汉

 思路:简单来说,就是将类的构造函数,拷贝构造函数,赋值运算符重载私有,和饿汉区别在于,随后定义的是一个静态的类对象指针,再给出一个静态的类对象的获取方法,这样保证了只有在定义一个类对象的时候才会真正的初始或这个类。

//不是线程安全
class Singleton
{
public:
	static Singleton* Instance()
	{
			if (_instance == nullptr)
			{
				_instance = new Singleton;
			}	
		return _instance;
	}
protected:
	Singleton()
	{
		cout<<"Create Singleton Obj."<<endl;
	}
private:
Singleton(){};
// 防拷贝
Singleton(Singleton const&);
Singleton& operator=(Singleton const&);
static Singleton* _instance;
};
Singleton* Singleton::_instance = nullptr;
void thread_fun(int n)
{
	for(int i=0; i<n; ++i)
	{
		Singleton *ps = Singleton::Instance();
		cout<<"ps = "<<ps<<endl;   //一样
	}
}
void main()
{
	system("pause");
	Singleton *pst = Singleton::Instance();
	Singleton *pst1 = Singleton::Instance();
	Singleton *pst2 = Singleton::Instance();
	Singleton *pst3 = Singleton::Instance();
}

 但以上程序在多线程情况下是不安全的,要想到到线程安全,可以加锁,同时我们使用双检机制提高效率。
 双检机制意味着当显出判断_instance != nullptr)时,说明对象已经被实例,直接返回该对象。

mutex mt;
//不是线程安全
class Singleton
{
public:
	static Singleton* Instance()
	{
		if(_instance == nullptr)  //双检锁  //双检机制
		{
			mt.lock();
			if (_instance == nullptr)
			{
				_instance = new Singleton;
			}
			mt.unlock();
		}
		
		return _instance;
	}
protected:
	Singleton()
	{
		cout<<"Create Singleton Obj."<<endl;
	}
private:
	static Singleton* _instance;
};
Singleton* Singleton::_instance = nullptr;
void thread_fun(int n)
{
	for(int i=0; i<n; ++i)
	{
		Singleton *ps = Singleton::Instance();
		cout<<"ps = "<<ps<<endl;   //一样
	}
}
void main()
{
	thread t1(thread_fun, 10);
	thread t2(thread_fun, 10);
	t1.join();
	t2.join();
}

 但其实我们在实际应用中,并不太会采用以上的做法,我们会定义一个单例的模板类,随后用该模板类和我们要创建的类实例化一个特定的类对象。这个模板类其实我和我们上面实现的单例类是一样的,只是将其变为模板(这个模板类目前还不是线程安全,要想达到线程安全,就必须和我们刚才讲的一样,加锁)。

template<typename T>
class LASingletonTemplateBase
{
private:
	static T* sm_instance;
protected:
	LASingletonTemplateBase()
	{
		assert(sm_instance == 0);
		sm_instance = static_cast<T*>(this);
	}
	virtual ~LASingletonTemplateBase()
	{
		assert(sm_instance != 0);
		sm_instance = 0;
	}
public:
	static T* get_instance_ptr()
	{
		if (sm_instance == 0)
		{
			sm_instance = new T();
		}
		return sm_instance;
	}
	static T& get_instance_ref()
	{
		if (sm_instance == 0)
		{
			sm_instance = new T();
		}
		return *sm_instance;
	}
	static void remove_instance()
	{
		assert(sm_instance);
		if (sm_instance)
		{
			delete sm_instance;
		}
		assert(sm_instance == 0);
	}
};
template<typename T>
T* LASingletonTemplateBase<T>::sm_instance = 0;
class Test
{};
void main()
{
	Test t1, t2, t3;
	Test *pt1 = LASingletonTemplateBase<Test>::get_instance_ptr();
	Test *pt2 = LASingletonTemplateBase<Test>::get_instance_ptr();
	Test *pt3 = LASingletonTemplateBase<Test>::get_instance_ptr();
}

其实这个原理我们提供继承一个父类来实现一个类不能拷贝。一般来说,如果我们要实现一个类不能被拷贝,可以讲类的拷贝构造函数和赋值运算符重载私有或者删除。但是这样做比较麻烦,当我们需要多个类不能被拷贝的话,在每个类中将其拷贝构造函数和赋值运算符重载私有或者删除是非常麻烦的。而通过继承一个不能被拷贝的父类就可以一步实现。

class noncopyable
{
protected:
	noncopyable() {}
	~noncopyable() {}
private:  // emphasize the following members are private
	noncopyable(const noncopyable&);
	const noncopyable& operator=(const noncopyable&);
};
class Test : public noncopyable
{
public:
	Test(int data = 0) :m_data(data)
	{}
	Test(const Test &t)
	{
		m_data = t.m_data;
	}
private:
	int m_data = 0;
};
class Test1 : public noncopyable
{
};
void main()
{
	 Test t1;
	 Test t2 = t1;   //
	 Test t3;
	 t3 = t1;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值