У меня есть интерфейс для звукового драйвера / плеера, который имеет такие функции, как SoundHandle Load(bfs::path)
и void Play(SoundHandle)
.Реализации предоставляются в виде плагинов / общих библиотек
Идея такова: загруженный звук возвращается через дескриптор с минимальным интерфейсом.Если этот дескриптор уничтожен, звук выгружается.Когда плагин выгружается, все дескрипторы становятся недействительными.
Моя реализация использует shared_ptr
с пользовательским удалителем, подобным этому:
/// Base class for a sound descriptor managed by the driver
struct SoundDesc : boost::noncopyable
{
virtual ~SoundDesc() {}
bool isValid() const { return isValid_; }
protected:
explicit SoundDesc() : isValid_(true) {}
bool isValid_;
};
class SoundHandle
{
public:
typedef boost::shared_ptr<SoundDesc> Descriptor;
explicit SoundHandle(Descriptor descriptor = Descriptor()) : descriptor_(descriptor) {}
/// Return true if the sound is still valid/loaded
bool isValid() const { return (!descriptor_) ? false : descriptor_->isValid(); }
/// Function for the driver to query the descriptor
const Descriptor& getDescriptor() const { return descriptor_; }
private:
Descriptor descriptor_;
};
И создание тогда:
SoundHandle AudioDriver::CreateSoundHandle(SoundDesc* sound)
{
sounds_.push_back(sound);
namespace bl = boost::lambda;
using bl::_1;
return SoundHandle(
SoundHandle::Descriptor(sound, bl::if_(bl::bind(&SoundDesc::isValid, _1))
bl::bind(&AudioDriver::UnloadSound, boost::ref(*this), _1)]
.else_[bl::bind(bl::delete_ptr(), _1)]));
}
Это общий код в базовом классе для плагинов, конкретные классы вызывают его с указателем на специфический для реализации подкласс SoundDesc (например, содержащий пользовательские данные) AudioDriver::UnloadSound
- это статический метод, выполняющий то, что предлагает имя.
Это работает хорошо, но когда плагин выгружается раньше всех SoundHandles, я получаю ошибку сегментации в dtor файла shared_ptr.Похоже, что код, сгенерированный лямбдой, живет в пространстве разделяемой библиотеки и при выгрузке исчезает, оставляя меня с висящим указателем.
Как это можно решить?
Толькоу меня есть идея, что SoundHandle хранит слабый_птр и драйвер shared_ptrs, чтобы слабый_птр не вызывал код плагина, когда он уже равен 0. Но это сделает время жизни звуков равным времени жизни плагина, хотя звук больше не можетиспользоваться.