2013-04-17 2 views
-1

В моем коде у меня есть класс SoundManager, который содержит и работает со всеми звуками для моей игры. Этот класс должен быть создан, и его методы называются несколькими другими классами. Однако я желаю только одного набора звуков, занимающих память, поэтому в интересах эффективности все активы объявляются как static 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 конкретизируется в моей основной функции() и каждый раз, когда мне нужно загрузить titlescreen (Soundmanager конкретизируется в этом titlescreen классе тоже). Инициализация и уничтожение экрана заголовка снова и снова не вызывают проблем. Статические объекты shared_ptrs не уничтожаются, поскольку они все еще используются экземпляром основных функций SoundManager.

Теперь все это работает на практике для запуска моей игры. Однако когда дело доходит до выхода из строя, когда статические объекты выше демонтируются, на меня бросаются необработанные исключения времени выполнения (нарушения доступа). С отладчиком VS2012, указывающим на строку в памяти.h.

private: 
    virtual void _Destroy() 
     { // destroy managed resource 
     delete _Ptr;  <<<<<<<<<The debugger points to this line 
     } 

Я должен был понять, что похож на Obj-C, C++ shared_ptrs использовать эталонные счетчики, чтобы гарантировать, что объекты не удаляются, пока объект не существует, что требует их использования больше. Я не понимаю, что может вызвать эти ошибки.

Возможно, важная часть, которую я не должен опускать: моя игра завершена вызовом для выхода (0); как можно ближе к функции main(). Я не предпринимал никаких действий для очистки членов SoundManager до этого, поскольку я думал, что shared_ptr обработал это.

Кто-нибудь знает, что может вызвать проблемы с моей очисткой?

+2

какого типа shared_ptr это они? Вызов 'reset()' на 'std :: shared_ptr' или' boost :: shared_ptr' очистит это 'shared_ptr', если он последний, ссылающийся на объект, тогда объект будет удален, если объект еще не был общий. – mark

+0

Вы уверены, что poitners не используются повторно? Если 'sEngine-> addSoundSourceFromFile' дважды возвращает один и тот же указатель, он дважды удаляется, потому что вы назначаете его двум различным' shared_ptr', которые не знают друг о друге.Или, если 'sEngine' вызывает delete на одном из указателей,' shared_ptr' будет нелегко очистить то, чего там нет. Запишите значение указателя, которое вызывает нарушение прав доступа, и попытайтесь сломать любое удаление, которое пытается освободить этот точный адрес. –

+0

'boost :: shared_ptr' имеет функции-члены, которые позволяют вам определить, является ли' shared_ptr' уникальным или получить его счетчик ссылок. – mark

ответ

1

Вы используете библиотеку IRRKLang. Эта библиотека поставляется в виде предварительно скомпилированного двоичного файла (dll, если вы находитесь в окнах). Эта библиотека делает себя бинарной совместимой, используя чистые виртуальные базы. Это работает, но вы не можете удалить объект для такой библиотеки, потому что ваша новая/удаленная программа отличается от новой/удаленной библиотеки. Эти типы библиотек предоставляют способ освободить память, это приведет к этому случаю.

Чтобы использовать shared_ptr и т. Д., Вы должны использовать пользовательский деаэратор. Взгляните на Using custom deleter with std::shared_ptr, чтобы узнать, как это сделать и изменить его в соответствии с вашими потребностями.

В вашем случае, поскольку вы используете Visual Studio 2012, вероятно, можно сделать что-то вроде этого

template<class T> 
struct IrrDeleter{ 
    void operator()(T* t){ 
     t->drop(); 
    } 
}; 

затем изменить все свои линии сброса, чтобы включить Deleter, например

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

Спасибо, я думаю, что это то, что мне нужно. Итак, вы говорите, что метод shared_ptrs для удаления данных, которые он содержит, конфликтует с IRRKlang's ISoundEngine по управлению собственной памятью, когда он выходит за рамки? –

+0

В некотором смысле. Ваше удаление (даже если руководство за пределами shared_ptr) не будет работать для ISoundEngine. Это связано с тем, что удаление и удаление IrrKlang отличаются друг от друга, поскольку IrrKlang, вероятно, скомпилирован с другой библиотекой компилятора/стандартной библиотеки. Все классы Irrklang, полученные из IRefCounted, которые предоставляют метод drop, который удалит его правильно –

1

Если вы хотите вручную освободить ресурс, используемый shared_ptr, вам необходимо позвонить по телефону reset. Что касается использования статического shared_ptr, я не думаю, что получаю рассуждения. Все дело в том, что они не копируют ресурс, поэтому у вас будет только один ресурс.

+0

Я решил сделать указатели shared_ptrs, потому что они статические, и я только хотел, чтобы там был один экземпляр объекта, на который они указывают, хотя и на всю программу, при этом все еще есть несколько экземпляров класса SoundManager. Однако сделать их «shared_ptr» один не делает этого, поэтому я сделал их статичными. Объясняет ли это мои рассуждения? –

Смежные вопросы