【发布时间】:2013-07-01 10:48:40
【问题描述】:
许多 C API 提供了带有 **p 的释放函数,除了释放资源之外,还设置了指向 NULL 的指针。
我想用带有自定义删除器的boost::shared_ptr 包装此类 C API 调用。
这是一个使用 FFMPEG 的示例:
AVFrame* frame = av_frame_alloc(); // allocate resource
// Do stuff with frame
av_frame_free(&frame) // free resource
为了利用 RAII,我可以这样重写:
AVFrame* frame = av_frame_alloc();
boost::shared_ptr<AVFrame*> frame_releaser(&frame, av_frame_free);
// Do stuff with frame
注意shared_ptr<> 是<AVFrame*> 类型,而不是<AVFrame> 作为指针类型。
这种方法需要我分别持有资源和释放者,这有几个缺点:
-
frame可能会在外部更改导致泄漏。 - 它需要 2 个变量而不是 1 个变量,这使得代码更容易出错。
我想使用单个shared_ptr 变量来保存资源并在需要时释放它。
本着 boost::ref 的精神,我希望编写或使用 通用 address_of_arg_wrapper 作为删除器,这样我就可以编写如下内容:
boost::shared_ptr<AVFrame> frame_handle(av_frame_alloc(), address_of_arg_wrapper(av_frame_free));
// Do stuff with frame_handle.get()
或
boost::shared_ptr<AVFrame> frame_handle(av_frame_alloc(), address_of_arg_wrapper<av_frame_free>());
// Do stuff with frame_handle.get()
包装器必须是通用的并接受任何指针(ref)类型,这一点很重要,因此它可以与任何此类 API 函数一起使用。
我也不想指定类型。
Boost 有这样的实用程序吗?
如果不是,那怎么能写出这样一个泛型函子呢?
编辑 - 完整性解决方案:
此解决方案基于@R. Martinho Fernandes's answer below。
- 它包含一个模板函数来创建模板函子,因此无需指定模板类型。
- 代码取决于
boost::decay。仅包含Fun fun;成员的版本也适用于我测试的简单案例。 - 我把名字改成了
arg_ref_adaptor()。欢迎提供更好的名称建议!
代码如下:
#include <boost\type_traits\decay.hpp>
//////////////////////////////////////////////////////////////////////////
// Given a function or callable type 'fun', returns an object with
// a void operator(P ptr) that calls fun(&ptr)
// Useful for passing C API function as deleters to shared_ptr<> which require ** instead of *.
template <typename Fun>
struct arg_ref_adaptor_functor
{
public:
arg_ref_adaptor_functor(Fun fun): fun(fun) {}
template <typename P>
void operator()(P ptr)
{ fun(&ptr); }
private:
typename boost::decay<Fun>::type fun;
};
template <typename Fun>
inline arg_ref_adaptor_functor<Fun> arg_ref_adaptor(Fun fun)
{ return arg_ref_adaptor_functor<Fun>(fun); }
用法:
boost::shared_ptr<AVFrame> frame_handle(::av_frame_alloc()
,arg_ref_adaptor(::av_frame_free));
// Do stuff with frame_handle.get()
// The resource will be released using ::av_frame_free() when frame_handle
// goes out of scope.
【问题讨论】:
-
IMO 你应该 typedef boost::shared_ptr 因为 C++11 有 std::shared_ptr,并且你希望在升级编译器时尽量减少迁移工作。
-
@Bathsheba 我会保持命名空间清晰。将 boost::shared_ptr 批量替换为 std::shared_ptr 可以在一秒钟内完成。而混合命名空间是危险的。
-
@billz:这很酷;只要我们牢记迁移。
-
我正在考虑是否提及
boost::shared_ptr和std::shared_ptr,但我认为这不是重点。使用 Boost 很明显,来自 Boost 的解决方案(a-laboost::ref是可以接受的)。
标签: c++ boost shared-ptr