+ -
当前位置:首页 → 问答吧 → 彻底崩溃的VS2005 DLL之Singleton模板

彻底崩溃的VS2005 DLL之Singleton模板

时间:2011-12-15

来源:互联网

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
C/C++ code

//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
C/C++ code

//测试体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
C/C++ code


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


作者: mcmcmc   发布时间: 2011-12-15

有一行贴错了
template<class Tp> TSingleton<Tp>::TSingleton(Tp* pThis,const std::string& strT):CSingleton(strT)

作者: mcmcmc   发布时间: 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
请按任意键继续. . .

作者: mcmcmc   发布时间: 2011-12-15

珍惜生命,远离扩展dll,只使用纯C接口的标准dll

作者: taodm   发布时间: 2011-12-15