单例模式是一个非常经常使用的设计模式,在每一本讲述设计模式的书籍中都会提到。关于单例模式的设计初衷不再多说,这篇文章将把重点放到单例的c++实现上。
在开始之前还要讲述一下,我自己在学习设计模式的时候,书籍中的全部实例都是以Java程序作为实例讲解的,而由于Java语音的特性使得许多在单例中应该注意的问题都被屏蔽,而这些问题在c++中都爆发出来。下面开始文章正文,先以一个模仿Java的单例C++程序开始。
头文件
class MySingleton{
public:
static MySingleton *instance();
private:
explicit MySingleton();
static MySingleton *_instance;
}
源文件
MySingleton *MySingleton::_instance = 0;
MySingleton *MySingleton::instance()
{
if(0 == _instance)
{
_instance = new MySingleton();
}
return _instance;
}
MySingleton::MySingleton()
{
}
好,按照Java的示例程序,写到这里一个单例已经出来了。注意,接下来的话不是否定书籍中所说的单例内容,因为设计模式讲述的是思想,选择了Java进行实例
分析,这里使用另一种语音,侧重于实现。
作为C++程序员,一个重要工作是编写析构函数,我们为这个单例加上一个析构函数。
修改后头文件如下
class MySingleton {
public:
static MySingleton *instance();
virtual ~MySingleton();
private:
explicit MySingleton();
static MySingleton *_instance;
}
修改后源文件如下
MySingleton *MySingleton::_instance = 0;
MySingleton *MySingleton::instance()
{
if(0 == _instance)
{
_instance = new MySingleton();
}
return _instance;
}
MySingleton::~MySingleton()
{
delete _instance;
}
MySingleton::MySingleton()
{
}
如果你在项目中如此实现单例的话,可能带来巨大的隐患。假设如下场景:A和B协同开发使用了这个类,A使用Instance进行逻辑,B使用Instance进行逻辑,接着只要其中一个人把这个单例delete掉,那另一位同学使用Instance时将使用的是悬空指针。因为析构函数中并没有把_instance指回0,而是一个非法地址。
所以我们需要向析构函数添加将_instance指回0的代码。上述这些问题在Java程序中是不会发生的,因为Java中对象一销毁就指向null。
我们的讨论还没有结束,大部分书籍讲述了单例的创建过程,很少有书籍讲述它的销毁,或者说谈论它是否应该被销毁。如果他应该可以被销毁,上述的例子够用。如果它不该被销毁,怎么办?难道要把析构函数也申明为private吗?不是所有编译器都支持这个做法。所以,就我目前遇到的最好的解决办法,就是告诉你的小伙伴,不要在代码中delete单例,这样,销毁的事情就不会发生。
(这是我的第一篇博客,如果你认为文章中存在错误或者你有什么疑惑的话,请留言。另外转发请注明出处,谢谢!)