现在的位置: 首页 > 综合 > 正文

设计模式的Singleton模式的分析

2012年11月10日 ⁄ 综合 ⁄ 共 3255字 ⁄ 字号 评论关闭

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;
}

抱歉!评论已关闭.