我有一个声音驱动程序/播放器的界面,具有 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之前卸载时,我在shared_ptr的dtor中出现了分段错误 . 看起来lambda生成的代码存在于共享库的空间中,并且在卸载时它会消失,因为它留下了一个悬空指针 .

怎么解决这个问题?

我只有想法是让SoundHandle存储一个weak_ptr和驱动程序shared_ptrs,这样当它已经为0时,weak_ptr将不会调用插件代码 . 但这会使声音的生命周期等于插件的生命周期,尽管声音可能没有更长时间使用 .