删除智能指针指向的对象

Deleting objects pointed to by smart pointers

本文关键字:对象 智能 指针 删除      更新时间:2023-10-16

在我的代码中,我有一个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>());