彻底崩溃的VS2005 DLL之Singleton模板

I_ask_who 2011-12-15 09:16:50
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.h

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"));
}
};

//测试体02.cpp

CTest2::CTest2(void):TSingleton(this,"CTest2"){}



MFC EXT DLL01

//测试体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.cpp
CTest5::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;
}
};

MFC console Exe文件,Depends on Dll00,Dll01


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;
}

...全文
197 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
qscool1987 2011-12-16
  • 打赏
  • 举报
回复
这也太长了吧。。。
qq120848369 2011-12-16
  • 打赏
  • 举报
回复
在windows下做这种事难度总是很大,毛病很多。
I_ask_who 2011-12-16
  • 打赏
  • 举报
回复
写了这个模板,然后兴致勃勃的用在了17个类上,结果崩溃,再重新返工,实在不行就用宏.做了一个小程序实验*就是上面那个,发现这个问题.
结论是不要在MFC Dll中使用带有static变量的template(继承方式;组合方式没有试过),特别是跨Dll引用,好像Exe跨Dll可以,Dll跨Dll则出现怪异现象.
taodm 2011-12-15
  • 打赏
  • 举报
回复
珍惜生命,远离扩展dll,只使用纯C接口的标准dll
I_ask_who 2011-12-15
  • 打赏
  • 举报
回复
Console输出如下
CTest2 created: 1
fail to load class's instance: unknown
Call Fail 2
duplicate!
CTest2 created: 2
GetpInstance() success: unknown
Hello Test2CTest20
CTest5 created: 1
GetpInstance() success: CTest5
Hello Test5
deleted: CTest2
deleted: CTest5
请按任意键继续. . .
I_ask_who 2011-12-15
  • 打赏
  • 举报
回复
有一行贴错了
template<class Tp> TSingleton<Tp>::TSingleton(Tp* pThis,const std::string& strT):CSingleton(strT)

64,649

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧