在我的代码中,我有一个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也在这个titlescreen类中实例化)。一遍又一遍地初始化和销毁标题屏幕不会导致问题。静态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处理了这个。
有人知道可能导致我清理问题的原因吗?
答案 0 :(得分:1)
如果您想手动释放shared_ptr
使用的资源,则需要致电reset
。至于使用静态shared_ptr
我不认为我得到了推理。重点是他们不会复制资源,所以你只有一个资源。
答案 1 :(得分:1)
您正在使用IRRKLang库。这个库是一个预编译的二进制文件(如果你在Windows上,则为dll)。该库通过使用纯虚拟库使自身二进制兼容。这样可以,但是你不能删除这样的库的对象,因为你的程序new / delete与库的新/删除不同。这些类型的库提供了一种释放内存的方法,这种情况下降了。
要使用shared_ptr等,您必须使用自定义删除器。请查看Using custom deleter with std::shared_ptr,了解如何操作并根据自己的需要进行修改。
在您使用Visual Studio 2012的情况下,您可以执行类似这样的操作
template<class T>
struct IrrDeleter{
void operator()(T* t){
t->drop();
}
};
然后更改所有重置行以包含删除器,例如
sEngine.reset(createIrrKlangDevice(),IrrDeleter<ISoundEngine>());