单例模式

懒汉模式:

方案一:局部静态实例

class Singleton
{
public:
	static Singleton& instance()
	{
		static Singleton instance;
		return instance;
	}

private:
	Singleton() {}
	~Singleton() {}
	Singleton(const Singleton &) {}
	Singleton& operator=(const Singleton &) {}
}
单线程下安全,多线程下不安全,因为编译器是通过局部静态变量来标记局部静态实例是否已经初始化的,没有加锁就存在竞争。


方案二:局部静态实例加锁

class Singleton
{
public:
	static Singleton& instance()
	{
		Lock();
		static Singleton instance;
		UnLock();
		return instance;
	}
	
private:
	Singleton() {}
	~Singleton() {}
	Singleton(const Singleton &) {}
	Singleton& operator=(const Singleton &) {}
}
每次调用instance()时都要加锁,系统开销大。


方案三:静态成员指针变量

class Singleton
{
public:
	static Singleton& instance()
	{
		if (pInstance_ == NULL)
		{
			Lock();
			if (pInstance_ = NULL)
				pInstance_ = new Singleton();
			UnLock();
			return *pInstance_;
		}
		return *pInstance_;
	}
	
private:
	Singleton() {}
	Singleton(const Singleton &) {}
	Singleton& operator=(const Singleton &) {}
	
	static Singleton* volatile pInstance_;
}

Singleton* volatile Singleton::pInstance_ = NULL
线程安全,系统开销小,但是无法释放资源


方案四:方案三的基础添加Garbo类

class Singleton
{
public:
	static Singleton& instance()
	{
		if (NULL == pInstance_)
		{
			Lock();
			if (NULL == pInstance_)
			{
				pInstance_ = new Singleton();
				static Garbo garbo;
			}
			UnLock();
			return *pInstance_;
		}
		return *pInstance_;
	}

	class Garbo
	{
	public:
		~Garbo()
		{
			cout << "~Garbo" << endl;
			if (Singleton::pInstance_ != NULL)
				delete Singleton::pInstance_;
		}
	};

private:
	Singleton() {}
	~Singleton() {cout << "~Singleton" << endl;}
	Singleton(const Singleton &) {}
	Singleton& operator=(const Singleton &) {}

	static Singleton* volatile pInstance_;
};

Singleton* volatile Singleton::pInstance_ = NULL;
需要时才创建单例,线程安全,系统开销小,程序结束时释放资源。

用模板实现:

template <typename T>
class Singleton
{
public:
	static T& instance() //虽然定义的是指针成员,返回引用表示Singleton的生存期由自己决定
	{
		if (NULL == pInstance_)
		{
			Lock();
			if (NULL == pInstance_)
			{
				pInstance_ = new T();
				static Garbo garbo;
			}
			UnLock();
			return *pInstance_;
		}
		return *pInstance_;
	}

	class Garbo
	{
	public:
		~Garbo()
		{
			if (T::pInstance_ != NULL)
				delete T::pInstance_;
		}
	};

protected: //构造函数和析构函数定义成保护成员是希望派生类可以访问
	Singleton() {}
	~Singleton() {} //防止外部调用单例的地址进行delete

private:
	Singleton(const Singleton &) {}
	Singleton& operator=(const Singleton &) {}

	static T* volatile pInstance_;
};

template <typename T>
T* volatile Singleton<T>::pInstance_ = NULL;

class Test:public Singleton<Test>
{

};

int main()
{
	Test::instance();
	return 0;
}

饿汉模式:

方案五:静态成员实例

class Singleton
{
public:
	static Singleton& instance()
	{
		return instance_;
	}
	
private:
	static Singleton instance_;
	
	Singleton() {}
	~Singleton() {}
	Singleton(const Singleton &) {}
	Singleton& operator=(const Singleton &) {}
}

Singleton Singleton::instance_;
在进入main函数之前就已经初始化静态实例,不存在多线程竞争问题,涉及到资源释放可以放在析构函数里面执行。

虽然方案三看起来已经很符合线程安全的问题了,但如果在单例的构造函数里面调用另一个单例类就可能有问题了。例如:

//.h
class Manager
{
public:
	static Manager& instance() {return instance_;}

private:
	static Manager instance_;

	Manager();
	Manager(const Manager &) {}
	Manager& operator=(const Manager &) {}
};

class Staff
{
public:
	static Staff& instance() {return instance_;}
	void doSomething();

private:
	static Staff instance_;

	Staff();
	Staff(const Staff &) {}
	Staff& operator=(const Staff &) {}
};

//.cpp
Manager::Manager() 
{	
	cout << "Manager Constructor" << endl; 
	Staff::instance().doSomething();
}

Staff::Staff()
{
	cout << "Staff Constructor" << endl;
}

void Staff::doSomething()
{
	cout << "Staff doSomething" << endl;
}

Manager Manager::instance_;
Staff Staff::instance_;
程序开始后,在进入mani函数前,执行到{Manager Manager::instance_;}语句时,调用了Manager构造函数,Manager构造函数调用了Staff::instance(),此时Staff::instance_还没初始化。
实际测试结果程序没有崩溃,应该是静态数据区已经为静态实例分配了空间,只是还没调用构造函数而已,所以输出结果是:
Manager Constructor
Staff doSomething
Staff Constructor


方案六:boost的实现方式:单例对象作为静态局部变量,但增加一个辅助类让单例对象可以在一开始就初始化

//.h
class Manager
{
public:
	static Manager& instance()
	{
		static Manager instance;
		return instance;
	}

private:
	struct ObjectCreator
	{
		ObjectCreator()
		{
			Manager::instance();
		}
		inline void doNothing() const {}
	};

	static ObjectCreator create_object_;

	Manager();
	Manager(const Manager &) {}
	Manager& operator=(const Manager &) {}
};

class Staff
{
public:
	static Staff& instance()
	{
		static Staff instance;
		return instance;
	}

	void doSomething();

private:
	struct ObjectCreator
	{
		ObjectCreator()
		{
			Staff::instance();
		}
		inline void doNothing() const {}
	};

	static ObjectCreator create_object_;

	Staff();
	Staff(const Staff &) {}
	Staff& operator=(const Staff &) {}
};

//.cpp
Manager::Manager()
{
	cout << "Manager Constructor" << endl;
	Staff::instance().doSomething();
}

Staff::Staff()
{
	cout << "Staff Constructor" << endl;
}

void Staff::doSomething()
{
	cout << "Staff doSomething" << endl;
}

Manager::ObjectCreator Manager::create_object_;
Staff::ObjectCreator Staff::create_object_;
在进入main函数前
->初始化Manager::create_object_;
->调用ObjectCreator的构造函数;
->调用Manager::instance()初始化局部Manager单例;
->执行Manager构造函数;
->调用Staff::instance()初始化局部Staff单例;
->执行Staff构造函数;
->返回局部Staff单例,调用doSomething()函数。

跟方案五的区别在于Manager调用Staff单例时,前者是取到静态成员实例,该实例尚未初始化,而后者是取静态局部实例,此时会初始化该实例。

用模板实现:

template <typename T>
struct Singleton
{
	struct ObjectCreator
	{
		ObjectCreator()
		{
			Singleton<T>::instance();
		}
		inline void doNothing() const {}
	};
	
	static ObjectCreator create_object_;
	
public:
	typedef T ObjectType;
	static ObjectType& instance()
	{
		static ObjectType obj;
		//这个doNothing是为了确保create_object_构造函数被调用
		create_object_.doNothing();
		return obj;	
	}
};

template <typename T> 
typename Singleton<T>::ObjectCreator Singleton<T>::create_object_;

class Manager
{
public:
	void doSomething(){}
	
protected:
	Manager() {}
	~Manager() {}
	friend class Singleton<Manager>;
};

int main()
{
	Singleton<Manager>::instance().doSomething();
}

总结:

六种方案,满足线程安全的单例只有方案四和方案六,个人觉得方案四比较好理解,方案六的技巧比较怪。


本文参考自:

C++单例实现的坑 http://blog.cnbang.net/tech/2229/

面试中的Singleton http://www.cnblogs.com/loveis715/archive/2012/07/18/2598409.html








  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值