-1

在我的代码中,我有一个 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 也在这个标题屏幕类中实例化)。一遍又一遍地初始化和销毁​​标题屏幕不会导致问题。静态 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 已经处理了这个问题。

有人知道是什么导致我的清理问题吗?

4

2 回答 2

2

如果要手动释放 a 使用的资源,shared_ptr则需要调用reset. 至于使用静态shared_ptr,我认为我没有得到推理。关键是它们不会复制周围的资源,因此您将只有一个资源。

于 2013-04-17T15:01:26.530 回答
1

您正在使用 IRRKLang 库。该库以预编译二进制文件的形式提供(如果您在 Windows 上,则为 dll)。该库通过使用纯虚拟库使其自身二进制兼容。这可行,但是您不能像这样删除库的对象,因为您的程序 new/delete 与库的 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>());
于 2013-04-17T15:38:52.747 回答