设计模式之单例(singleton)模式

#ifndef _SINGLETON_H
#define _SINGLETON_H
#include <assert.h>
//单例模式是一种常用的软件设计模式。
//在它的核心结构中只包含一个被称为单例类的特殊类。
//通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,
//从而方便对实例个数的控制并节约系统资源。
//如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。

template <class T>
class Singleton
{
public:
 //获取类的唯一实例
 static inline T* instance()
 {
  return _instance;
 }
 //释放类的唯一实例
protected:
 Singleton(void){assert(!_instance);_instance = (T*)this;_instance = (T*)this;}
 ~Singleton(void){assert(_instance);_instance = 0;}
 static T* _instance;
};

template<class T>
T* Singleton<T>::_instance = NULL;
//cpp文件中需要先声明静态变量
#define DECLARE_SINGLETON_MEMBER(_Ty) \
 template <> _Ty* Singleton<_Ty>::_instance = NULL;

#endif//_SINGLETON_H


全面的考虑:

单例模式  保证一个类只有一个实例,并提供一个访问它的全局访问点

所谓只有一个实例 那就让别人不能随便new 只能从类的一个静态方法得到它的实例,构造函数设为私有的即可

class Singleton
{
private:
static Singleton* Instance;
private:
Singleton();
public:

static Singleton* GetInstance();

};

代码实现:

#include "StdAfx.h"
#include "Singleton.h"
Singleton*  Singleton::Instance = NULL;

Singleton::Singleton(void)
{
}
Singleton* Singleton::GetInstance()
{
if(Instance == NULL)
{
Instance = new Singleton();
}
return Instance;
}

貌似很OK,但是其实我们这边的入口点,不是只有一个的

当我们没有拷贝构造函数和赋值函数的时候,编译器会默认生成一个,所以说程序的入扣点除了现在的静态函数外,还有默认的其他函数

那怎么办呢?

好办,直接将这些函数设为私有的,不实现即可,代码如下

class Singleton

{

private:

static Singleton* Instance;

private:

Singleton();

Singleton(const Singleton&);

Singleton& operator=(const Singleton&);

public:

static Singleton* GetInstance();

};

实现代码同上

那现在怎么样,貌似还有问题,我们看GetInstance()的实现

如果有多个线程进行这个函数调用,会发生什么,会出现创建多个实例,并导致内存泄露

怎么办,加锁

锁文件代码如下:

Lock.h

#include<Windows.h>

class Lock

{

public:
Lock(void);
~Lock(void);
void RequireLock();
void ReleaseLock();
private:
CRITICAL_SECTION m_lock;

};

Lock.cpp

#include "StdAfx.h"
#include "Lock.h"
#include<Windows.h>

Lock::Lock(void)
{

InitializeCriticalSection(&m_lock);
}

Lock::~Lock(void)
{
DeleteCriticalSection(&m_lock);
}
void Lock::RequireLock()
{
EnterCriticalSection(&m_lock);
}
void Lock::ReleaseLock()
{
LeaveCriticalSection(&m_lock);
}

那单例类代码如下:

Singleton.h

#pragma once
#include "Lock.h"
class Singleton
{
private:

static Singleton* Instance;
static  Lock* myLock;
private:
  Singleton();

Singleton(const Singleton&);

Singleton& operator=(const Singleton&);

public:

static Singleton* GetInstance();

    
};

Singleton.cpp

#include "StdAfx.h"
#include "Singleton.h"
Singleton*  Singleton::Instance = NULL;
Lock*  Singleton::myLock = new Lock();
Singleton::Singleton(void)
{
}
Singleton* Singleton::GetInstance()
{
myLock->RequireLock();
if(Instance == NULL)
{
Instance = new Singleton();
}
myLock->ReleaseLock();
return Instance;
}
一切似乎无懈可击,可是当考虑到我们的对象时new出来的,我们需要销毁它,怎么办,将析构函数拿出来调用,我想既然有一个全局的入口点,就应该有一个全局的出口点,再定义一个静态函数,用于销毁new出来的对象,并将析构函数设为私有的

可是问题来了,销毁也有new相同的问题,如果不进行同步的法,一个对象会销毁两次,也会有内存泄露,那我们只用再加一把锁即可,可是还有一种情况,当一个线程创建实例的时候,另外一个线程正在销毁它,好吧,这也需要同步,不能我正在创建的时候,你在销毁它,对象肯定是乱的了

所以不管创建和销毁,我们必须要得到两把锁,一把是用于管理对象创建,一把用于管理对象销毁,不管你是创建和销毁对象,你必须保证先得到这两把锁,保证在任一时刻只有一个线程在创建或者销毁

代码如下:

Singleton.h

class Singleton
{
private:
static Singleton* Instance;
static  Lock* myLock;
static Lock* myDeleteLock;
private:
Singleton();
  Singleton(const Singleton&);

Singleton& operator=(const Singleton&);

 ~Singleton();


public:

static Singleton* GetInstance();

static void DestroyInstance();
};

Singleton.cpp

Singleton*  Singleton::Instance = NULL;
Lock*  Singleton::myLock = new Lock();
Lock*  Singleton::myDeleteLock = new Lock();
Singleton::Singleton(void)
{
}
Singleton::~Singleton(void)
{

}
Singleton* Singleton::GetInstance()
{

myLock->RequireLock();

myDeleteLock->RequireLock();

if(Instance == NULL)
{
Instance = new Singleton();
}
myDeleteLock->ReleaseLock();
myLock->ReleaseLock();
return Instance;
}
void Singleton::DestroyInstance()
{
myLock->RequireLock();
myDeleteLock->RequireLock();
if(Instance != NULL)
{
delete Instance;
Instance = NULL;
}
myDeleteLock->ReleaseLock();
myLock->ReleaseLock();
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值