Сделать ручку закрытой с обеих сторон - PullRequest
0 голосов
/ 10 декабря 2018

У меня есть интерфейс для звукового драйвера / плеера, который имеет такие функции, как 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. Но это сделает время жизни звуков равным времени жизни плагина, хотя звук больше не можетиспользоваться.

...