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
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;}
原文链接: https://www.cnblogs.com/xianyunhe/archive/2011/07/04/2097503.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/28090
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!