以下為Singleton.h:
class HungerSingleton
{
private:
class CGarbo // 用於析構s_pInstance
{
public:
~CGarbo()
{
if(HungerSingleton::s_pInstance)
delete HungerSingleton::s_pInstance;
}
};
static CGarbo Garbo;
static HungerSingleton *s_pInstance;
public:
static HungerSingleton * GetInstance()
{
return s_pInstance;
}
};
下為Singleton.cpp:HungerSingleton* HungerSingleton::s_pInstance = new HungerSingleton;
測試函數:void TestSingleton()
{
HungerSingleton *phgl = HungerSingleton::GetInstance();
}
為什麼Garbo作為靜態變量沒有在類外部定義,而程序卻沒有報錯呢?
測試環境:VS2013的優化已禁用 (/Od),警告等級 4 (/W4)
因為你的 static CGarbo Garbo;的 CGarbo類裡面並沒有數據成員,CGarbo是一個空類,所以sizeof(CGarbo)==1; 如果CGarbo的public(為了測試方便)加上一個數據成員char c,另外在HungerSingleton類的GetInstance()加上cout << Garbo.c << "\n"; 那麼sizeof(CGarbo)還是==1; 但是在我加上char c以後,你的CGarbo有了數據成員,此時執行我給你的新改裝類,則會滿滿的報錯,error LINK2001(不解釋),因為對於無數據成員的類,編譯器會產生於有數據成員的類不同的目標代碼,所以加上char c以後,類的目標碼不同,而且編譯器知道你用了未初始化的Garbo.c,如果你不在外部顯示提供初始化,是通不過的。但是你去掉cout << Garbo.c << "\n";這句,可以通過,因為編譯器在編譯的時候發現你自始至終沒用過Garbo的.c,故不影響鏈接,不會報錯。
另外補充一句,現在的編譯器很智能,即使在10年前,Silicon Graphics的N32和N64編譯器已經能自動為所有型別提供適當的type_traits的特化版本,進行STL優化。10年過去了,編譯器技術突飛猛進,如果你懂匯編,去調整編譯器的優化級別,反復觀察匯編碼,你就知道編譯器給你優化了什麼了。(我用的的/Od)
最有給你我改的代碼,注釋部分你好好看看,如果你去掉cout << Garbo.c << "\n";的注釋,就會報錯。此時你再去掉首位的注釋去初始化,問題就OK了。
#include
using std::cout;
class HungerSingleton
{
private:
class CGarbo // 用於析構s_pInstance
{
public:
//CGarbo(char c) :c(c){ }
char c;
~CGarbo()
{
if (HungerSingleton::s_pInstance)
delete HungerSingleton::s_pInstance;
}
};
static CGarbo Garbo;
static HungerSingleton *s_pInstance;
public:
static HungerSingleton* GetInstance()
{
//cout << Garbo.c << "\n";
cout << sizeof(CGarbo) << "\n";
return s_pInstance;
}
};
HungerSingleton* HungerSingleton::s_pInstance = new HungerSingleton;
//HungerSingleton::CGarbo HungerSingleton::Garbo('a');
void TestSingleton()
{
HungerSingleton *phgl = HungerSingleton::GetInstance();
}
int main()
{
TestSingleton();
return 0;
}
你的問題非常好,我學習了。祝你事業進步,生活快樂!