C++ 删除智能指针指向的对象

C++ 删除智能指针指向的对象,c++,memory-management,smart-pointers,irrklang,C++,Memory Management,Smart Pointers,Irrklang,在我的代码中,我有一个SoundManager类,它包含并操作我游戏中的所有声音。这个类需要被实例化,它的方法需要被其他多个类调用。然而,我希望只有一组声音占用内存,因此为了提高效率,所有资产都声明为静态共享\u ptr #include "SoundManager.h" static shared_ptr<ISoundEngine> sEngine; static shared_ptr<ISoundSource> hoverSound; static shared_

在我的代码中,我有一个SoundManager类,它包含并操作我游戏中的所有声音。这个类需要被实例化,它的方法需要被其他多个类调用。然而,我希望只有一组声音占用内存,因此为了提高效率,所有资产都声明为静态共享\u ptr

#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.h”
静态共享引擎;
静态共享_ptr hoverSound;
静态共享确认声音;
静态共享ptr mainBGM;
静态共享接口;
SoundManager::SoundManager(无效)
{
//首先,我们需要创建irrKlang声音引擎实例
如果(!sEngine)
{
sEngine.reset(createIrrKlangDevice());
}
如果(!hoverSound)hoverSound.reset(sEngine->addSoundSourceFromFile(“Sounds/ButtonHover.mp3”);
如果(!confirmSound)confirmSound.reset(sEngine->addSoundSourceFromFile(“Sounds/ButtonConfirm.mp3”);
如果(!mainBGM)mainBGM.reset(sEngine->addSoundSourceFromFile(“Sounds/mainBGM.mp3”);
//设置一些默认卷
hoverSound->setDefaultVolume(1.0f);
确认声音->设置默认音量(0.4f);
mainBGM->setDefaultVolume(0.5f);
}
SoundManager::~SoundManager(无效)
{   
}
这个SoundManager在我的main()函数中实例化,每次我需要加载标题屏幕时(SoundManager也在这个titlescreen类中实例化)。反复初始化和销毁标题屏幕不会导致问题。静态共享_ptrs对象不会被销毁,因为SoundManager的主要功能实例仍在使用它们

现在,这一切在运行我的游戏的实践中都很好。然而,当涉及到干净地退出时,当上面的静态对象被拆除时,未处理的运行时异常(访问冲突)就会向我抛出。VS2012的调试器将我指向内存中的一行

private:
    virtual void _Destroy()
        {   // destroy managed resource
        delete _Ptr;       <<<<<<<<<The debugger points to this line
        }
private:
虚拟空间_Destroy()
{//销毁托管资源

删除如果你想手动释放一个
共享的
使用的资源,你需要调用。至于使用静态
共享的
我想我不明白原因。关键是他们不复制周围的资源,所以你只有一个资源。

你正在使用的是IRRKLang库。这个库y作为预编译二进制文件(如果您在windows上,则为dll)。此库通过使用纯虚拟基使其自身与二进制兼容。这是可行的,但您不能删除类似库的对象,因为您的程序new/delete与库的new/delete不同。这些类型的库提供了一种释放内存的方法,本例中为drop

要使用shared_ptr等,您必须使用自定义删除程序。请查看如何执行此操作,并根据您自己的需要对其进行修改

在您的情况下,因为您使用的是Visual Studio 2012,所以您可能可以执行类似的操作

template<class T>
struct IrrDeleter{
   void operator()(T* t){
       t->drop();
   }
};
模板
结构IrrDeleter{
void运算符()(T*T){
t->drop();
}
};
然后更改所有重置行以包括删除程序,例如

sEngine.reset(createIrrKlangDevice(),IrrDeleter<ISoundEngine>());
sEngine.reset(createIrrKlangDevice(),IrrDeleter());

它们是什么类型的共享ptr?调用
reset()
std::shared_ptr
boost::shared_ptr
上,将清除
shared_ptr
,如果它是引用该对象的最后一个,则该对象将被删除,如果该对象不是共享的,则该对象仍将被共享。是否确定不会重用该指针?如果
sEngine->addSoundSourceFromFile
返回相同的指针t因此,它会被删除两次,因为您将它分配给两个不同的
shared\u ptr
s,它们彼此不了解。或者如果
sEngine
在其中一个指针上调用delete,那么
shared\u ptr
将很难清除不再存在的内容。记下导致访问viol的指针值在试图释放该确切地址的任何删除操作中,您都可以删除并尝试中断。
boost::shared_ptr
具有成员函数,允许您确定
shared_ptr
是否唯一或获取其引用计数。@mark我以为只有一种类型的shared_ptr?(顺便说一句,我最初是用unique ptrs'来做这件事的,但它产生了同样的问题)。@ArneMertz
sEngine->addSoundSourceFromFile()
返回指向类型为
ISoundSource
的新对象的指针。我决定让指针共享,因为它们是静态的,我只希望它们指向的对象有一个实例,而不考虑整个程序,同时仍然有
SoundManager
类的多个实例。是否可以de>sEngine
或任何与此相关的对象,获取最初由
共享\u ptr
管理的指针的所有权,并在原始拥有共享\u ptr没有对此发表意见的情况下将其删除?除非我调用reset()在一个愚蠢的地方?我决定让指针共享,因为它们是静态的,我只想在整个程序中有一个它们指向的对象实例,同时仍然有SoundManager类的多个实例。但是,单独让它们“共享”并不能做到这一点,这就是为什么我让它们是静态的。不是吗他的解释解释了我的理由?谢谢,我想这就是我需要的。那么你是说共享的删除它所持有的数据的方式与IRRKlang的ISoundEngine在超出范围时管理自己内存的方式相冲突吗?在某种程度上。你的删除(即使是手动删除)不适用于ISoundEngine。这是因为您的delete和IrrKlang delete不同,因为IrrKlang可能是使用不同的编译器/标准库编译的。从IRefCounted派生的所有IrrKlang类都提供了正确删除它的drop方法