我有一个声音驱动程序/播放器界面,其功能类似于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,因此,当soft_ptr已经为0时,它不会调用该插件代码。但这将使声音的生命周期等于该插件的生命周期,尽管声音可能不再使用。