单例模式总结(C++)




单例模式:保证在整个程序中只有一个实例,并提供一个各个程序模块都可以访问的接口。


一、常用标准模式:


#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.csdn.net/hackbuteer1/article/details/7460019
http://www.jellythink.com/archives/82
http://blog.csdn.net/roy1261/article/details/51425987
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值