单例模式:保证在整个程序中只有一个实例,并提供一个各个程序模块都可以访问的接口。
一、常用标准模式:
#include <iostream>
using namespace std;
class Singleton
{
private:
Singleton() :m_x(10){}
int m_x;
static Singleton *m_instance;
public:
static Singleton* GetInstance()
{
if (m_instance == NULL)
{
m_instance = new Singleton();
}
return m_instance;
}
static void DestoryInstance()
{
if (m_instance != NULL)
{
delete m_instance;
m_instance = nullptr;
}
}
int GetX()
{
return m_x;
}
};
Singleton *Singleton::m_instance = nullptr;
int main()
{
cout << Singleton::GetInstance()->GetX() << endl;
Singleton::DestoryInstance();
return 0;
}
这种模式有两个缺点:
1.必须手动删除实例
注意:系统并不能自动回收new出的对象,当遇到单例类的析构函数中有必要的操作的时候,如:关闭文件,释放外部
资源,这是必须要删除实例。
2.在多线程实现的程序中,不能保证只生成一个实例,比如在第一个线程进入if (m_instance == NULL)后生成实例之前,另
一个进程也进入了此if语句的情况,就会产生两个实例
二、针对第一个缺点的改进:
#include <iostream>
using namespace std;
class Singleton
{
private:
Singleton() :m_x(10){}
~Singleton(){ cout << "Singleton 析构函数" << endl; }
int m_x;
static Singleton *m_instance;
public:
static Singleton* GetInstance()
{
if (m_instance == NULL)
{
m_instance = new Singleton();
}
return m_instance;
}
class GC
{
public:
~GC()
{
if (m_instance != nullptr)
{
delete m_instance;
m_instance = nullptr;
cout << "GC 析构函数" << endl;
system("pause"); // 注意让程序在这里暂停才能看到结果
}
}
};
static GC gc; //注意!必须是静态成员,否则属于Singleton的实例同意不会析构
int GetX()
{
return m_x;
}
};
Singleton *Singleton::m_instance = nullptr;
Singleton::GC Singleton::gc; // 类的静态成员变量必须在外部初始化,否则gc不会被构造,更不会析构
int main()
{
cout << Singleton::GetInstance()->GetX() << endl;
return 0;
}
原理:程序结束时系统会自动释放类的静态成员变量(和全局变量),所以当成员变量gc被释放时会调用它的析
构函数,进而delete m_instance。
在这个原理的基础之上,又有另一种方法:
#include <iostream>
using namespace std;
class Singleton
{
private:
Singleton() :m_x(10){}
int m_x;
public:
static Singleton& GetInstance()
{
static Singleton instance;
return instance;
}
int GetX()
{
return m_x;
}
void Setx(int _x)
{
m_x = _x;
}
};
int main()
{
Singleton ss = Singleton::GetInstance(); //两个实例!!!
ss.Setx(5);
cout << Singleton::GetInstance().GetX() << endl;
cout << ss.GetX() << endl;
system("pause");
return 0;
}
这种方法的优点是简化了代码,但也有缺点:
从上面的main函数中可以看出,通过默认的拷贝构造函数创造了另一个实例,所以又有对应改进:
#include <iostream>
using namespace std;
class Singleton
{
private:
Singleton() :m_x(10){}
int m_x;
public:
static Singleton* GetInstance()
{
static Singleton instance;
return &instance;
}
int GetX()
{
return m_x;
}
void Setx(int _x)
{
m_x = _x;
}
};
int main()
{
Singleton *p = Singleton::GetInstance();
cout << p->GetX() << endl;
system("pause");
return 0;
}
也就是把引用换成了指针。
或者通过声明私有拷贝和重置=运算符禁止赋值:
#include <iostream>
using namespace std;
class Singleton
{
private:
Singleton() :m_x(10){}
Singleton(const Singleton &);
void operator = (const Singleton &);
int m_x;
public:
static Singleton& GetInstance()
{
static Singleton instance;
return instance;
}
int GetX()
{
return m_x;
}
void Setx(int _x)
{
m_x = _x;
}
};
int main()
{
cout << Singleton::GetInstance().GetX() << endl;
system("pause");
return 0;
}
三、针对第二个缺点的改进
class Lock
{
private:
CCriticalSection m_cs;
public:
Lock(CCriticalSection cs) : m_cs(cs)
{
m_cs.Lock();
}
~Lock()
{
m_cs.Unlock();
}
};
class Singleton
{
private:
Singleton();
Singleton(const Singleton &);
Singleton& operator = (const Singleton &);
public:
static Singleton *Instantialize();
static Singleton *pInstance;
static CCriticalSection cs;
};
Singleton* Singleton::pInstance = 0;
Singleton* Singleton::Instantialize()
{
if(pInstance == NULL)
{ //double check
Lock lock(cs); //用lock实现线程安全,用资源管理类,实现异常安全
//使用资源管理类,在抛出异常的时候,资源管理类对象会被析构,析构总是发生的无论是因为异常抛出还是语句块结束。
if(pInstance == NULL)
{
pInstance = new Singleton();
}
}
return pInstance;
}
也就是所谓的“双检锁”机制。
如果进行大数据的操作,加锁操作将成为一个性能的瓶颈,因此改进:
/*
** FileName : SingletonPatternDemo3
** Author : Jelly Young
** Date : 2013/11/20
** Description : More information, please go to http://www.jellythink.com
*/
#include <iostream>
using namespace std;
class Singleton
{
public:
static Singleton *GetInstance()
{
return const_cast <Singleton *>(m_Instance);
}
static void DestoryInstance()
{
if (m_Instance != NULL )
{
delete m_Instance;
m_Instance = NULL ;
}
}
int GetTest()
{
return m_Test;
}
private:
Singleton(){ m_Test = 10; }
static const Singleton *m_Instance;
int m_Test;
};
const Singleton *Singleton ::m_Instance = new Singleton();
int main(int argc , char *argv [])
{
Singleton *singletonObj = Singleton ::GetInstance();
cout<<singletonObj->GetTest()<<endl;
Singleton ::DestoryInstance();
}
原文:因为静态初始化在程序开始时,也就是进入主函数之前,由主线程以单线程方式完成了初始化,
所以静态初始化实例保证了线程安全性。在性能要求比较高时,就可以使用这种方式,从而避免频繁的
加锁和解锁造成的资源浪费。
参考及代码引用相关文章:
http://blog.youkuaiyun.com/hackbuteer1/article/details/7460019
http://www.jellythink.com/archives/82
http://blog.youkuaiyun.com/roy1261/article/details/51425987