在我的代码中,我有一个SoundManager类,它包含并操作我的游戏的所有声音。这个类需要被实例化,并且它的方法可以被多个其他类调用。然而,我希望只有一组声音占用内存,因此为了提高效率,将所有资产声明为静态shared_ptrs。
#include "SoundManager.h"
static shared_ptr<ISoundEngine> sEngine;
static shared_ptr<ISoundSource> hoverSound;
static shared_ptr<ISoundSource> confirmSound;
static shared_ptr<ISoundSource> mainBGM;
static shared_ptr<ISound> bgmInterface;
SoundManager::SoundManager(void)
{
//first we need to create the irrKlang sound engine instance
if(!sEngine)
{
sEngine.reset(createIrrKlangDevice());
}
if(!hoverSound)hoverSound.reset(sEngine->addSoundSourceFromFile("Sounds/ButtonHover.mp3"));
if(!confirmSound)confirmSound.reset(sEngine->addSoundSourceFromFile("Sounds/ButtonConfirm.mp3"));
if(!mainBGM)mainBGM.reset(sEngine->addSoundSourceFromFile("Sounds/mainBGM.mp3"));
//set some default volumes
hoverSound->setDefaultVolume(1.0f);
confirmSound->setDefaultVolume(0.4f);
mainBGM->setDefaultVolume(0.5f);
}
SoundManager::~SoundManager(void)
{
}
这个SoundManager在我的main()函数中实例化,每次我需要加载标题屏幕(SoundManager也在这个titlesscreen类中实例化)。反复初始化和破坏标题屏幕并不会造成问题。静态shared_ptrs对象不会被销毁,因为它们仍然在SoundManager的主函数实例中使用。
现在这一切都工作良好的实践运行我的游戏。然而,当干净地退出时,当上面的静态对象被拆除时,未处理的运行时异常(访问违规)就会向我抛出。VS2012的调试器指向memory.h中的一行。
private:
virtual void _Destroy()
{ // destroy managed resource
delete _Ptr; <<<<<<<<<The debugger points to this line
}
与obj-c类似,c++ shared_ptrs使用引用计数器来确保对象不会被删除,直到不再存在需要使用它们的对象。我不明白是什么导致了这些错误。
也许我不应该忽略一个重要的部分:我的游戏是通过调用exit(0)退出的;尽可能接近main()函数。在这样做之前,我没有采取任何行动来清理SoundManagers成员,因为我认为shared_ptr处理了这个问题。
有谁知道是什么导致了我的清理问题吗?
如果您想手动释放shared_ptr
使用的资源,您需要调用reset
。至于使用静态shared_ptr
,我不认为我得到的理由。关键是它们不复制周围的资源,所以您将只有一个资源。
您正在使用IRRKLang库。这个库是一个预编译的二进制文件(如果你在windows上是dll)。这个库通过使用纯虚基来实现二进制兼容。这是可行的,但是你不能为这样的库删除对象,因为你的程序new/delete与库的new/delete不同。这些类型的库提供了一种释放内存的方法,在这种情况下是drop。
要使用shared_ptr等,必须使用自定义删除器。查看使用自定义删除器与std::shared_ptr,了解如何做到这一点,并根据自己的需要修改它。
在你的情况下,因为你使用的是Visual Studio 2012你可能会做这样的事情
template<class T>
struct IrrDeleter{
void operator()(T* t){
t->drop();
}
};
然后更改所有重置行以包含删除符,例如
sEngine.reset(createIrrKlangDevice(),IrrDeleter<ISoundEngine>());