DXUT库,CDXUTDialogResourceManager的一个不太好发现的问题

如果按照DXUT例子的编码方式,很难出现这个问题的,但是这两日闲来无事,将DXUT分到了一个DLL内,结果……
退出时报错!

不断注释代码,最后发现是CDXUTDialogResourceManager惹的祸。再一检查,有些心得,遂拿来共享。


原因是这样的:
CDXUTDialogResourceManager在析构函数里干掉Cache(Delete):
//--------------------------------------------------------------------------------------
CDXUTDialogResourceManager::~CDXUTDialogResourceManager()
{
inti;
for(i=0;i<m_FontCache.GetSize();i++)
{
DXUTFontNode*pFontNode=m_FontCache.GetAt(i);
SAFE_DELETE(pFontNode);
}
m_FontCache.RemoveAll();

for(i=0;i<m_TextureCache.GetSize();i++)
{
DXUTTextureNode*pTextureNode=m_TextureCache.GetAt(i);
SAFE_DELETE(pTextureNode);
}
m_TextureCache.RemoveAll();

CUniBuffer::Uninitialize();
CDXUTIMEEditBox::Uninitialize();
}
//--------------------------------------------------------------------------------------



而在OnDestroyDevice里真正Release这些资源:
//--------------------------------------------------------------------------------------
voidCDXUTDialogResourceManager::OnDestroyDevice()
{
inti=0;

m_pd3dDevice=NULL;

//Releasetheresourcesbutdon'tclearthecache,asthesewillneedtobe
//recreatedifthedeviceisrecreated
for(i=0;i<m_FontCache.GetSize();i++)
{
DXUTFontNode*pFontNode=m_FontCache.GetAt(i);
SAFE_RELEASE(pFontNode->pFont);
}

for(i=0;i<m_TextureCache.GetSize();i++)
{
DXUTTextureNode*pTextureNode=m_TextureCache.GetAt(i);
SAFE_RELEASE(pTextureNode->pTexture);
}

SAFE_RELEASE(m_pSprite);
}
//--------------------------------------------------------------------------------------
一般说来,在例子中,这个RM都是以全局变量形式存在的:
extern CDXUTDialogResourceManagerg_DialogResourceManager;//managerforsharedresourcesofdialogs

这就有一个问题,OnDestroyDevice和析构函数究竟哪个在先?这就要看OnDestroyDevice的最终调用者DXUTState这个全局变量和g_DialogResourceManager这个全局变量的析构先后顺序了。
一般,如果这些代码和您的代码都编译到一个EXE,则顺序大凡是先State析构,调用DestroyDevice再RM析构,这就对了,既Release又Delete。
而在将DXUT封到Dll后,便发生了位于Dll的State后于位于EXE的RM析构的情况,这导致了先调用了RM的析构函数,然后才调用了State析构和OnDestroyDevice!!!
这意味着先调用了Delete,然后在Release的时候就找不着北了,资源没有Release,DXUT自然会报错!

由此得出一个结论:VC的CRT在退出时,先干掉了EXE本身的全局变量,然后才去释放各个DLL……
写到这里后,又发现DXUTState是一个非导出类,遂导出之,结果依旧……
不知对否,遂又作测试,发现凡是EXE中的全局变量,全都在Dll的State前析构。
extern CDXUTDialogg_HUD;//dialogforstandardcontrols
extern CDXUTDialogg_SampleUI;//dialogforsamplespecificcontrols
皆如此。

解决的方案就近乎简单了,DialogRM既然都析构了,何不调用自己的Release?为何一定要在State析构时才调用呢?
因此为增加一句:
CDXUTDialogResourceManager::~CDXUTDialogResourceManager()
{
[color=blue] /////////////////////////////////////////////////
OnDestroyDevice();
/////////////////////////////////////////////////
[/color]
inti;
for(i=0;i<m_FontCache.GetSize();i++)
{
DXUTFontNode*pFontNode=m_FontCache.GetAt(i);
SAFE_DELETE(pFontNode);
}
m_FontCache.RemoveAll();

for(i=0;i<m_TextureCache.GetSize();i++)
{
DXUTTextureNode*pTextureNode=m_TextureCache.GetAt(i);
SAFE_DELETE(pTextureNode);
}
m_TextureCache.RemoveAll();

CUniBuffer::Uninitialize();
CDXUTIMEEditBox::Uninitialize();
}

去掉其他地方对RM的OnDestroyDevice的调用。
再编译连接,成功,不会再在退出时报错了。

结论:
该谁的事情谁自己处理,别让别人擦屁股,否则总会受人牵制。

欢迎大家指正^_^


你可能感兴趣的:(cache,vc++)