设计模式的Singleton模式的分析

Singleton模式要求类只能创建一个实体对象。刚开始学习单件模式之时,在网上搜了一下,发现实现的方式有多种多样,但很多实现方式都存在着一些缺陷,如内存泄露,野指针。尤其是野指针问题不好处理,因为野指针的产生是由调用者产生的。显然,CSingleton类的设计者并不能控制调用者对操作,但却可以限制调用者的调用方式。

下面通过几种不同的Singleton模式的实现方式来分析。

1、在CSingleton类中建立一个指向CSingleton类的指针的静态变量,在用户第一次调用实体化函数时对该变量进行分配空间。该方法就存在内存泄露的问题。为了阻止调用者对CSingleton类进行实例化,要把CSingleton类的构造函数、拷贝构造函数和赋值运算符都设为私有。为了防止出现野指针,也应该阻止用户对CSingleton类的指针进行释放。

 C++代码
   
     
#include " stdafx.h "
#include
< iostream >

using namespace std;

class CSingleton
{
private :
// 构造函数
CSingleton()
{
cout
<< " CSingleton Constructor!\n " ;
}

// 拷贝构造函数
CSingleton( const CSingleton & Src)
{
cout
<< " CSingleton Copy Constructor!\n " ;
}

// 赋值运算符
void operator = ( const CSingleton & Src)
{
cout
<< " CSingleton Copy Operator!\n " ;
}

// 析构函数
~ CSingleton()
{
cout
<< " CSingleton Destructor!\n " ;
}

private :

// 唯一的实体对象
static CSingleton * ms_pInstance;

public :

// 获得实体对象指针
static CSingleton * GetInstance()
{
if (NULL == ms_pInstance)
{
ms_pInstance
= new CSingleton();
}

return ms_pInstance;
}

// 测试函数
void Print()
{
cout
<< " Print CSingleton!\n " ;
}
};

CSingleton
* CSingleton::ms_pInstance = NULL;

int _tmain( void )
{
CSingleton
* pSingleton1 = CSingleton::GetInstance();
pSingleton1
-> Print();

CSingleton
* pSingleton2 = CSingleton::GetInstance();
pSingleton2
-> Print();

// 析构函数为私有,编译错误
// delete pSingleton1;

system(
" pause " );

return 0 ;
}


2、智能指针auto_ptr是防止内存泄露的有效方法,智能指针会执行动态分配内存对象的自动释放工作。因为auto_ptr在释放内存时,需要调用CSingleton类的析构函数,因此,必须把atuo_ptr<CSingleton>设为类的友元,以保证对象内存的释放。但如果auto_ptr在外部再次获得CSingle指针的占用权,将会导致错误,而且是编译器无法检测的错误,是一个潜在的危险。

 C++代码
   
     
#include " stdafx.h "
#include
< iostream >

using namespace std;

class CSingleton
{
private :
// 构造函数
CSingleton()
{
cout
<< " CSingleton Constructor!\n " ;
}

// 拷贝构造函数
CSingleton( const CSingleton & Src)
{
cout
<< " CSingleton Copy Constructor!\n " ;
}

// 赋值运算符
void operator = ( const CSingleton & Src)
{
cout
<< " CSingleton Copy Operator!\n " ;
}

// 析构函数
~ CSingleton()
{
cout
<< " CSingleton Destructor!\n " ;
}

public :

// 获得实体对象指针
static CSingleton * GetInstance()
{
static CSingleton s_Instance;
return & s_Instance;
}

// 测试函数
void Print()
{
cout
<< " Print CSingleton!\n " ;
}
};


int _tmain( void )
{
CSingleton
* pSingleton1 = CSingleton::GetInstance();
pSingleton1
-> Print();

CSingleton
* pSingleton2 = CSingleton::GetInstance();
pSingleton2
-> Print();

// 析构函数为私有,编译错误
// delete pSingleton1;

system(
" pause " );

return 0 ;
}


3、在GetInstance函数中创建一个静态变量,并把静态变量的指针返回给调用者。这种方式是我目前所了解的最优的实现方法,既没有内存泄露,也没有野指针的现象。但是,该方式在VC6.0下时编译不过的,是VC6.0的一个bug。还好现在,我已经升级到了VS2010。经过VS2010测试,可以顺利通过。估计VS2003以后的版本就能支持,但未具体测试过。

C++代码 
   
     
#include " stdafx.h "
#include
< iostream >
#include
< memory >

using namespace std;

class CSingleton
{
public :
friend
class auto_ptr < CSingleton > ;

private :
// 构造函数
CSingleton()
{
cout
<< " CSingleton Constructor!\n " ;
}

// 拷贝构造函数
CSingleton( const CSingleton & Src)
{
cout
<< " CSingleton Copy Constructor!\n " ;
}

// 赋值运算符
void operator = ( const CSingleton & Src)
{
cout
<< " CSingleton Copy Operator!\n " ;
}

// 析构函数
~ CSingleton()
{
cout
<< " CSingleton Destructor!\n " ;
}

private :

// 唯一的实体对象
/* static CSingleton* ms_pInstance; */
static auto_ptr < CSingleton > m_apInstance;

public :

// 获得实体对象指针
static CSingleton * GetInstance()
{
if ( ! m_apInstance. get ())
{
m_apInstance.reset(
new CSingleton());
}

return m_apInstance. get ();
}

// 测试函数
void Print()
{
cout
<< " Print CSingleton!\n " ;
}
};

auto_ptr
< CSingleton > CSingleton::m_apInstance;

int _tmain( void )
{
CSingleton
* pSingleton1 = CSingleton::GetInstance();
pSingleton1
-> Print();

CSingleton
* pSingleton2 = CSingleton::GetInstance();
pSingleton2
-> Print();

// 析构函数为私有,编译错误
// delete pSingleton1;

// 编译器无法检测的错误,多次释放内存
// auto_ptr<CSingleton> apSingleton(pSingleton1);

system(
" pause " );

return 0 ;
}

你可能感兴趣的:(Singleton)