Singleton模式是常用的设计模式之一Q但是要实现一个真正实用的设计模式却也不是件容易的事情?br />标准的实?/pre>
q是教科书上使用的方法。看h没有什么问题,其实包含很多的问题。下面我们一个一个的解决?/pre>
问题一 自动垃圾回收上面的程序必记住在E序l束的时候,释放内存。ؓ了让它自动的释放内存Q我们引入auto_ptr改变它?/pre>
问题? 增加模板在我的一个工E中Q有多个的Singletonc,对Singletonc,我都要实C面这一切,q让我觉得烦M。于是我惛_了模板来完成q些?br />复的工作?br />现在我们要添加本文中最吸引人单件实玎ͼ1 #include <memory>
2 using namespace std;
3 using namespace C2217::Win32;
4
5 namespace C2217
6 {
7 namespace Pattern
8 {
9 template <class T>
10 class Singleton
11 {
12 public:
13 static inline T* instance();
14
15 private:
16 Singleton(void){}
17 ~Singleton(void){}
18 Singleton(const Singleton&){}
19 Singleton & operator= (const Singleton &){}
20
21 static auto_ptr<T> _instance;
22 };
23
24 template <class T>
25 auto_ptr<T> Singleton<T>::_instance;
26
27 template <class T>
28 inline T* Singleton<T>::instance()
29 {
30 if( 0== _instance.get())
31 {
32 _instance.reset ( new T);
33 }
34
35 return _instance.get();
36 }
37
38 //Class that will implement the singleton mode,
39 //must use the macro in it's delare file
40 #define DECLARE_SINGLETON_CLASS( type ) \
41 friend class auto_ptr< type >;\
42 friend class Singleton< type >;
43 }
44 }问题? U程安全上面的程序可以适应单线E的E序。但是如果把它用到多U程的程序就会发生问题。主要的问题在于同时执行_instance.reset ( new T);
׃同时产生两个新的对象Q然后马上释放一个,q跟Singleton模式的本意不W。所以,你需要更加安全的版本Q?/pre>1 #include <memory>
2 using namespace std;
3 #include "Interlocked.h"
4 using namespace C2217::Win32;
5
6 namespace C2217
7 {
8 namespace Pattern
9 {
10 template <class T>
11 class Singleton
12 {
13 public:
14 static inline T* instance();
15
16 private:
17 Singleton(void){}
18 ~Singleton(void){}
19 Singleton(const Singleton&){}
20 Singleton & operator= (const Singleton &){}
21
22 static auto_ptr<T> _instance;
23 static CResGuard _rs;
24 };
25
26 template <class T>
27 auto_ptr<T> Singleton<T>::_instance;
28
29 template <class T>
30 CResGuard Singleton<T>::_rs;
31
32 template <class T>
33 inline T* Singleton<T>::instance()
34 {
35 if( 0 == _instance.get() )
36 {
37 CResGuard::CGuard gd(_rs);
38 if( 0== _instance.get())
39 {
40 _instance.reset ( new T);
41 }
42 }
43 return _instance.get();
44 }
45
46 //Class that will implement the singleton mode,
47 //must use the macro in it's delare file
48 #define DECLARE_SINGLETON_CLASS( type ) \
49 friend class auto_ptr< type >;\
50 friend class Singleton< type >;
51 }
52 }CresGuard cM要的功能是线E访问同?代码如下Q?/pre>
比如你有一个需要实现单件模式的c,应该这样实玎ͼ
在用的时候很单,跟一般的Singleton实现的方法没有什么不同?/pre>
一个简单的Singleton模式的实玎ͼ可以看到C++语言背后隐藏的丰富的语意Q我希望有h能实C个更好的Singleton让大家学习?/pre>
其中sum为carry为当前位之前的倹{?/p>
str[len-1-i]-'0'是表C将字符的ascii码减?的ascii码,最后出来的数字是需要的数字?/p>
每次*10的话把当前位往前移了?/p>
*改进了算法,增加了支持负敎ͼ以及到有问题的字符׃throw exception
重新又看了一遍二叉树(Binary Tree)Q发现很多东西自p没有弄明白,原来三种遍历方式q不是自己想象中的那?/p>
前序遍历(PreOrder)是先输出自己Q然后左Q最后右?/p>
中序遍历(InOrder)是先左,再输己,最后右?/p>
后序遍历(PostOrder)是先左,再右Q最后输己?/p>
所谓的XX遍历是指把自己攑֜哪个优先位置上,而不是指从哪里开始遍历?/p>
下来其实搜索匹配也可以用这个方法,基本上就是以递归形成的?/p>
另外q需要研I一下DFS(Depth First Search)以及BFS(Breadth First Search)的算法?/p>
单例模式有许多种实现ҎQ在C++中,甚至可以直接用一个全局变量做到q一点,但这L代码昄很不优雅?使用全局对象能够保证方便地访问实例,但是不能保证只声明一个对?#8212;—也就是说除了一个全局实例外,仍然能创建相同类?strong>本地实例?/p>
《设计模式》一书中l出了一U很不错的实玎ͼ定义一?strong>单例c?/strong>Q用类?strong>U有静态指针变?/strong>指向cȝ唯一实例Qƈ用一?strong>公有的静态方?/strong>获取该实例?/p>
单例模式通过cLw来理其唯一实例Q这U特性提供了解决问题的方法。唯一的实例是cȝ一个普通对象,但设计这个类Ӟ让它只能创徏一个实例ƈ提供 Ҏ实例的全局讉K。唯一实例cSingleton在静态成员函C隐藏创徏实例的操作。习惯上把这个成员函数叫做Instance()Q它的返回值是?一实例的指针?/p>
定义如下Q?/p>
用户讉K唯一实例的方法只有GetInstance()成员函数。如果不通过q个函数QQ何创建实例的试都将p|Q因为类的构造函数是U有的。GetInstance()使用懒惰初始?/strong>Q也是说它的返回值是当这个函数首ơ被讉K时被创徏的。这是一U防弹设?#8212;—所有GetInstance()之后的调用都q回相同实例的指针:
CSingleton* p1 = CSingleton :: GetInstance();
CSingleton* p2 = p1->GetInstance();
CSingleton & ref = * CSingleton :: GetInstance();
对GetInstanceE加修改Q这个设计模板便可以适用于可变多实例情况Q如一个类允许最多五个实例?/p>
单例cCSingleton有以下特征:
它有一个指向唯一实例的静态指针m_pInstanceQƈ且是U有的;
它有一个公有的函数Q可以获取这个唯一的实例,q且在需要的时候创实例Q?/p>
它的构造函数是U有的,q样׃能从别处创徏该类的实例?/p>
大多数时候,q样的实现都不会出现问题。有l验的读者可能会问,m_pInstance指向的空间什么时候释攑֑Q更严重的问题是Q该实例的析构函C么时候执行?
如果在类的析构行Z有必ȝ操作Q比如关闭文Ӟ释放外部资源Q那么上面的代码无法实现q个要求。我们需要一U方法,正常的删除该实例?/p>
可以在程序结束时调用GetInstance()Qƈ对返回的指针掉用delete操作。这样做可以实现功能Q但不仅很丑陋,而且Ҏ出错。因L附加代码很容易被忘记Q而且也很难保证在delete之后Q没有代码再调用GetInstance函数?/p>
一个妥善的Ҏ是让q个c自q道在合适的时候把自己删除Q或者说把删除自q操作挂在操作pȝ中的某个合适的点上Q其在恰当的时候被自动执行?/p>
我们知道Q程序在l束的时候,pȝ?strong>自动析构所有的全局变量。事实上Q系l也会析构所有的cȝ静态成员变量,像q些静态成员也是全局变量一栗利用这个特征,我们可以在单例类中定义一个这L静态成员变量,而它的唯一工作是在析构函C删除单例cȝ实例。如下面的代码中的CGarboc(Garbo意ؓ垃圾工hQ:
cCGarbo被定义ؓCSingleton的私有内嵌类Q以防该c被在其他地Ҏ用?/p>
E序q行l束Ӟpȝ会调用CSingleton的静态成员Garbo的析构函敎ͼ该析构函C删除单例的唯一实例?/p>
使用q种Ҏ释放单例对象有以下特征:
在单例类内部定义专有的嵌套类Q?/p>
在单例类内定义私有的专门用于释放的静态成员;
利用E序在结束时析构全局变量的特性,选择最l的释放时机Q?/p>
使用单例的代码不需要Q何操作,不必兛_对象的释放?/p>
(出处Q?a >http://hi.baidu.com/csudada/blog/item/208fb0f56bb61266dcc47466.html)
q一步的讨论
但是d一个类的静态对象,L让h不太满意Q所以有人用如下Ҏ来重现实现单例和解决它相应的问题Q代码如?/div>
使用局部静态变量,非常强大的方法,完全实现了单例的Ҏ,而且代码量更,也不用担心单例销毁的问题?/p>
但用此U方法也会出现问题,当如下方法用单例时问题来了Q?/p>
Singleton singleton = Singleton :: GetInstance();
q么做就出现了一个类拯的问题,q就q背了单例的Ҏ。生这个问题原因在于:~译器会为类生成一个默认的构造函敎ͼ来支持类的拷贝?/p>
最后没有办法,我们要禁止类拯和类赋|止E序员用q种方式来用单例,当时领导的意思是GetInstance()函数q回一个指针而不是返回一个引用,函数的代码改为如下:
关于Singleton(const Singleton); ?Singleton & operate = (const Singleton&); 函数Q需要声明成U用的,q且只声明不实现。这P如果用上面的方式来用单例时Q不是在友元类中还是其他的Q编译器都是报错?/p>
不知道这L单例cL否还会有问题Q但在程序中q样子用已l基本没有问题了?/p>
Q出处:http://snailbing.blogbus.com/logs/45398975.htmlQ?/p>
优化Singletonc,使之适用于单U程应用
Singleton使用操作Wnew为唯一实例分配存储I间。因为new操作W是U程安全的,在多U程应用中你可以使用此设计模板,但是有一?strong>~陷Q?是在应用程序终止之前必L工用delete摧毁实例。否则,不仅D内存溢出Q还要造成不可预测的行为,因ؓSingleton的析构函数将Ҏ不会 被调用。而通过使用本地静态实例代替动态实例,单线E应用可以很Ҏ避免q个问题。下面是与上面的GetInstance()E有不同的实玎ͼq个实现?门用于单U程应用Q?/p>
本地静态对象实例inst是第一ơ调用GetInstance()时被构造,一直保持活动状态直到应用程序终止,指针m_pInstance变得多余q且可以从类定义中删除掉Q与动态分配对象不同,静态对象当应用E序l止时被自动销毁掉Q所以就不必再手动销毁实例了?/p>
Q出处:http://blog.csdn.net/pingnanlee/archive/2009/04/20/4094313.aspxQ?/p>
代码学习Q从http://apps.hi.baidu.com/share/detail/32113057引用Q?/p>
其中比较隄解的是linka*& headQ传入的其实是linka *的类型就可以了,linka *是表Clinkacd的指针,&表示head的地址Q也是linka的指?/p>
另外需要熟悉的是head->nextQ其实有点像C#中的head.NextQ就是structure中的一个属?
首先定义3个指针,分别是前中后Q然后当中间那个指针非空Q就是当前不是空Q就做@环里的事?/p>
注意的是q个法里面next是在循环里面赋值的
每次循环都把current指向previous了,然后大家都往后移一个,next=current->next必须在current改变方向之前做,否则改变了方向之后current的next变成previous了?/p>
最后蟩出@环之后,header的next首先|空Q因为head变成了最后一个node了。然后head变成了previousQ因为当?current和next都ؓNULL了,只有previous为最后一个节点(或者说q时候应该是W一个非I点,也就是headQ?/p>
l于把整个算法理解了一遍,最后想惛_实挺单,但是能用c++写出来也不太ҎQ特别是在面试的时候?/p>
再增加一个递归的单链表反{的方法: