單件模式,像所有的同志一樣我也在用,不過(guò)不幸的是我走上了
歧途。鑒于對(duì)社會(huì)強(qiáng)烈地責(zé)任感(吐),我認(rèn)為有必要做個(gè)簡(jiǎn)要
的總結(jié)來(lái)避免后人步我的后塵(狂吐)。
那么現(xiàn)在開(kāi)始寫(xiě)正式的悔過(guò)書(shū)。
首先,首先清一下嗓子,哈哈。
再次,醞釀一下感情。
最后,再清一下嗓子,OK,THATS ALL,^_^.
所有有正義感的人都在向我扔鼠標(biāo),有的人開(kāi)始搬起顯示器。好
,好,在這種躁動(dòng)下,不利于我誠(chéng)心接受犯下的滔天錯(cuò)誤,請(qǐng)大
家少安毋躁,請(qǐng)看下下面的代碼:
template <typename T> class Singleton
{
protected:
T* ms_Singleton;//此行黏貼錯(cuò)誤,前面應(yīng)該加 STATIC
public:
Singleton( void )
{
assert( !ms_Singleton );
ms_Singleton = static_cast<T*>(this);
}
~Singleton( void )
{ assert( ms_Singleton ); ms_Singleton = 0; }
static T& getSingleton( void )
{ assert( ms_Singleton ); return (
*ms_Singleton ); }
static T* getSingletonPtr( void )
{ return ( ms_Singleton ); }
};
非常明顯,這段代碼是無(wú)懈可擊的,嘿嘿。出品人( Paul D
Turner)。
那么看看我糟糕的表現(xiàn):
class Application: public Singleton<Application>
{
public:
static Application* getSingletonPtr();
static Application getSingletonP();
void Run();
}
明眼人一眼就看出了端倪,我犯了個(gè)超級(jí)錯(cuò)誤,那就是
Application getSingletonPtr();
這是致命的缺陷,直接導(dǎo)致了單件模式的失敗,這樣的寫(xiě)法首先
語(yǔ)法上是說(shuō)的過(guò)去的,但事實(shí)上我并沒(méi)有重載
Application& getSingleton();所以當(dāng)我在別的類中用
Application::getSingleton()時(shí)出現(xiàn)了讓我眼前發(fā)黑的一暮。
因?yàn)楫?dāng)程序剛剛跳出調(diào)用這個(gè)方法的方法時(shí)(like that:
void ClassRoot::RunApplication
{
Application::getSingleton().Run();
}
)
,Application的析構(gòu)函數(shù)被調(diào)用,結(jié)果可想而知,Application
中的所有的資源都被釋放。接著系統(tǒng)無(wú)情的扔出一個(gè)面目可憎的
窗體,對(duì)我進(jìn)行了最為嚴(yán)厲的批評(píng),這個(gè)批評(píng)直接導(dǎo)致了你在此
消磨時(shí)間。特別聲名,由此對(duì)你青春的耽擱,從刑法上講,我不
會(huì)負(fù)主要責(zé)任,^_^.
“這是為什么”,我問(wèn)了同樣的問(wèn)題而且不只“千百遍”。我只
是沒(méi)有用引用而已,是的,引用,這的確是個(gè)問(wèn)題。就象用指針
一樣,引用也是沒(méi)有問(wèn)題地。前面程序失敗的原因是有新的臨時(shí)
Application實(shí)例產(chǎn)生,當(dāng)運(yùn)行完RunApplication時(shí),臨時(shí)對(duì)象
被釋放,他調(diào)用了析構(gòu)函數(shù),不幸的是,我在他里面釋放了一些
指針和資源,錯(cuò)誤產(chǎn)生了,他是如此的自然和順理成章。
引用,指針,我想有必要看看他們的貓膩所在。
LOOK一下下面的代碼:
#include "stdafx.h"
#include <string>
#include <iostream>
using namespace std;
class ouyang2008
{
public:
int a;
int b;
ouyang2008(){a=0;b=0;}
~ouyang2008(){}
void printtext()
{
//cout<<a<<endl<<b<<endl;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
ouyang2008* pObj=new ouyang2008;
//cout<<pObj<<endl;
ouyang2008& obj=*pObj;
ouyang2008* p=&obj;
delete pObj;
cout<<p;
return 0;
}
現(xiàn)在我們注意的焦點(diǎn)在:
ouyang2008& obj=*pObj;
ouyang2008* p=&obj;
看看他們有什么不同,那么我們?cè)趺碙OOK呢?WIN32 ASM,
yes,it is that:
ouyang2008& obj=*pObj;
00411556 mov eax,dword ptr [ebp-14h]
00411559 mov dword ptr [ebp-20h],eax
ouyang2008* p=&obj;
0041155C mov eax,dword ptr [ebp-20h]
0041155F mov dword ptr [ebp-2Ch],eax
哦,ALL is here ,so it is org.
從匯編上來(lái)看,他們沒(méi)有任何區(qū)別,他們都在函數(shù)的堆棧中保存
了一個(gè)對(duì)象的指針,所以當(dāng)退出函數(shù)時(shí)只是釋放了指針而已,對(duì)
對(duì)象沒(méi)有任何影響。
現(xiàn)在我們可以講:
對(duì)機(jī)器來(lái)說(shuō)他們沒(méi)有任何區(qū)別。
對(duì)使用者來(lái)講,咳、咳、咳,我不得不很無(wú)奈的重復(fù)別人所說(shuō)的
“引用是安全的”。
為什么是安全的?
第一,你不用擔(dān)心釋放的問(wèn)題。
第二呢,你不會(huì)很驚訝地看著讓你膽戰(zhàn)心驚的“EXCEPTION
ASSETT ERROR ox0000005 access invalidate”.
運(yùn)行以下下面的代碼:
#include "stdafx.h"
#include <string>
#include <iostream>
using namespace std;
class ouyang2008
{
public:
int* a;
int* b;
ouyang2008(){a=new int[1];b= new int[1];}
~ouyang2008(){delete[] a;delete[] b;a=b=NULL;}
void printtext()
{
cout<<*a<<endl<<*b<<endl;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
ouyang2008* pObj=new ouyang2008;
//cout<<pObj<<endl;
ouyang2008& obj=*pObj;
ouyang2008* p=&obj;
delete pObj;
if (p)//禍根
{
p->printtext();
}
cout<<p;
return 0;
}
當(dāng)然如果你現(xiàn)在的工作是對(duì)付。NET
你沒(méi)有必要注意這方面的問(wèn)題:
曾經(jīng)有為老兄在。NET還到處是臭蟲(chóng)的時(shí)候就這樣說(shuō)過(guò):
“對(duì)于。NET來(lái)講,任何類的對(duì)象都是在堆中建立的,類的變量
和對(duì)象之間只有引用,如果你在棧中看到了類的對(duì)象,那你就是
見(jiàn)到鬼了,而且是。NET鬼。”
呵呵,THAT IS OVER。
雙手合十,企求我不是在胡說(shuō)八道。