彻底崩溃的VS2005 DLL之Singleton模板
class Derived:public TSingleton<Derived>{}
继承自TSingleton<>模板,当new出Derived时,TSingleton<Derived>构造函数向静态变量Derived* s_pInstanceSingleton写入this值.调用TSingleton<>::GetpInstance()能够返回以前写入的this值
问题出在Dll上,使用的是MFC扩展Dll,使用Console调用.测试代码写在Dll01中,TSingleton写在Dll00中.两个Dll中分别定义了一个用于测试的Derived类,分别是CTest02和CTest05,代码几乎一模一样.
类似于
class AFX_EXT_CLASS CTest2:public TSingleton<CTest2>
{
public:
CTest2(void);
virtual ~CTest2(void){}
void SayHello(void)
{
std::cout<<"Hello Test2"<<m_strNameBase<<m_nSeq<<std::endl;
}
void SayHelloMsg(){
AfxMessageBox(_T("Hello Test2"));
}
};
CTest2::CTest2(void):TSingleton(this,"CTest2"){}
Dll01的用例"CTest05"没有问题,异地Dll00的用例 "CTest02"写入后调用GetpInstance返回是Null.后来用GetpInstance2返回了非Null值.但是对象被创建了2次.从Console输出可以看到.
更加诡异的是如果将CTest02的构造函数写在.h文件(class结构内)中,则没有问题.而写在.cpp中,即使加了inline也没有用
template的静态指针型变量 象蒸发了一样.
翻阅了Addison的C++ Templates: The Complete Guide 好像似乎有个章节是CRTP,不过没有深入展开.
安装的是VS2005sp1英文版,不知道是何原因?
MFC Ext Dll00
//Singleton.h,基础类,检查是否有违规class AFX_EXT_CLASS CSingleton{protected: static std::set<std::string> s_setStr;public: CSingleton(const std::string& strName); virtual ~CSingleton(void){}};//Singleton.cpp,基础类,检查是否有违规std::set<std::string> CSingleton::s_setStr;CSingleton::CSingleton(const std::string& strName){ if(s_setStr.find(strName)!=s_setStr.end()){ std::cout<<"duplicate!"<<std::endl; } s_setStr.insert(strName);}//TSingleton.h,模板类template<class Tp>class TSingleton:public CSingleton{protected: static Tp* s_pInstanceSingleton; static std::string s_strSingletonName; std::string m_strNameBase; static int m_nSeq;protected: TSingleton(Tp* pThis,const std::string& strT);/*:CSingleton(strT); { s_strSingletonName=strT; s_pInstanceSingleton=pThis; }*/ virtual ~TSingleton(void) { s_pInstanceSingleton=NULL; std::cout<<"deleted: "<<s_strSingletonName<<std::endl; }public: static Tp* GetpInstance() //with no auto create { if(s_pInstanceSingleton){ std::cout<<"GetpInstance() success: "<<s_strSingletonName<<std::endl; return s_pInstanceSingleton; } std::cout<<"fail to load class's instance: "<<s_strSingletonName<<std::endl; return NULL; } static Tp* GetpInstance2() //with auto create { if(s_pInstanceSingleton){ std::cout<<"GetpInstance2() success: "<<s_strSingletonName<<std::endl; return s_pInstanceSingleton; } s_pInstanceSingleton=new Tp; AfxMessageBox(_T("new instance")); return s_pInstanceSingleton; }};template<class Tp> Tp* TSingleton<Tp>::s_pInstanceSingleton;template<class Tp> std::string TSingleton<Tp>::s_strSingletonName="unknown";template<class Tp> int TSingleton<Tp>::m_nSeq=0;template<class Tp> TSingleton<Tp>::TSingleton(Tp* pThis,const std::string& strT):CSingleton(strT),s_pInstanceSingleton(pThis){ this->s_strSingletonName=strT; this->s_pInstanceSingleton=pThis; this->m_strNameBase=strT; this->m_nSeq++; std::cout<<m_strNameBase<<" created: "<<m_nSeq<<std::endl; //s_pInstanceSingleton=dynamic_cast<Tp*>(this);}//测试体02.hclass AFX_EXT_CLASS CTest2:public TSingleton<CTest2>{public: CTest2(void); virtual ~CTest2(void){} void SayHello(void) { std::cout<<"Hello Test2"<<m_strNameBase<<m_nSeq<<std::endl; } void SayHelloMsg(){ AfxMessageBox(_T("Hello Test2")); }};//测试体02.cppCTest2::CTest2(void):TSingleton(this,"CTest2"){}
//测试体05.h#include "stdafx.h"class AFX_EXT_CLASS CTest5:public TSingleton<CTest5>{public: CTest5(void); virtual ~CTest5(void); void SayHello(void); void SayHelloMsg();};//测试体05.cppCTest5::CTest5(void):TSingleton(this,"CTest5"){}CTest5::~CTest5(void){}void CTest5::SayHello(void){ std::cout<<"Hello Test5"<<std::endl;}void CTest5::SayHelloMsg(){ AfxMessageBox(_T("Hello Test5"));}//测试CTest02,CTest05#include "Test5.h"class AFX_EXT_CLASS CTestAll{public: CTestAll(void); virtual ~CTestAll(void);public: void TestConsole() { new CTest2; CTest2* pTest2=CTest2::GetpInstance(); if(pTest2){ pTest2->SayHello(); }else{ std::cout<<"Call Fail 2"<<std::endl; pTest2=CTest2::GetpInstance2(); CTest2::GetpInstance()->SayHello(); } new CTest5; CTest5* pTest5=CTest5::GetpInstance(); if(pTest5){ pTest5->SayHello(); }else{ std::cout<<"Call Fail 5"<<std::endl; pTest5=CTest5::GetpInstance2(); CTest5::GetpInstance()->SayHello(); } delete pTest2; delete pTest5; } void TestGui() { new CTest2; CTest2* pTest2=CTest2::GetpInstance(); if(pTest2){ pTest2->SayHelloMsg(); }else{ AfxMessageBox(_T("Call Fail 2")); pTest2=CTest2::GetpInstance2(); CTest2::GetpInstance()->SayHello(); } new CTest5; CTest5* pTest5=CTest5::GetpInstance(); if(pTest5){ pTest5->SayHelloMsg(); }else{ AfxMessageBox(_T("Call Fail 5")); pTest5=CTest5::GetpInstance2(); CTest5::GetpInstance()->SayHello(); } delete pTest2; delete pTest5; }};int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]){ int nRetCode = 0; // initialize MFC and print and error on failure if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0)) { // TODO: change error code to suit your needs _tprintf(_T("Fatal Error: MFC initialization failed\n")); nRetCode = 1; } else { CTestAll test; test.TestConsole(); } return nRetCode;}