如何为包装需要 2 个参数的 c 函数的 unique_ptr class 成员创建自定义删除器?
How do you create a custom deleter for a unique_ptr class member that wraps a c function which requires 2 arguments?
我正在尝试使用 mupdf 创建一个程序(在 Qt 中),它允许我将文档的对象列为列表,并允许我 select 渲染/不渲染哪些对象。由于 Qt 是 C++,而且我对它更熟悉,所以我尝试将 mupdf 中定义的结构包装在 C++ 类.
现在我的问题是 - 你在 mupdf 中做的第一件事就是创建一个全局上下文,它被传递给所有东西,包括清理和删除结构的函数。
我熟悉创建一个重载的对象 operator()
,很像:
struct ContextDeleter
{
inline void operator()(fz_context* ctx)
{
fz_drop_context(ctx);
}
};
然后我可以交给 unique_ptr
-
std::unique_ptr<fz_context, ContextDeleter> ctxPtr;
我想不通的是如何用像这样的函数做同样的事情:
fz_drop_page(ctx, page);
即:
struct PageDeleter
{
inline void operator()(fz_context* ctx, fz_page* pg)
{
fz_drop_page(ctx, pg);
}
}
这显然是不正确的,但正是我正在努力实现的目标。
如何为 unique_ptr
创建包含 2 个参数(在本例中为必要的上下文指针)的删除器?有没有办法让 unique_ptr
知道删除页面的上下文指针(在本例中)?或者(我曾想过)我是否需要创建一些东西来包装 unique_ptr
以便我可以稍后以某种方式将其删除的上下文(还没有完全考虑清楚)。
我看过这里的例子:
How do I use a custom deleter with a std::unique_ptr member?
和
Wrapping of C-code with a unique_ptr and custom deleter
但我不知道如何让它们在我的情况下工作。
将 fz_context *
存储在删除器中,并将该删除器的实例传递给包含 fz_page *
的 unique_ptr
struct PageDeleter
{
explicit PageDeleter(fz_context *ctx)
: ctx(ctx)
{}
void operator()(fz_page* page) const
{
fz_drop_page(ctx, page);
}
fz_context *ctx;
};
将unique_ptr
构造为
fz_context *ctx = // get the fz_context
fz_page *page = // get the fz_page
PageDeleter page_del(ctx);
std::unique_ptr<fz_page, PageDeleter> pagePtr(page, page_del);
为方便起见,您可以将所有这些包装在一个 make_unique_fz_page
函数中。
尝试使用捕获 fz_context*
值的 lambda,而不是将其存储在自定义删除器中:
fz_context *ctx = ...;
fz_page *page = ...;
std::unique_ptr<fz_page, std::function<void(fz_page*)>> pagePtr(page, [ctx](fz_page *page){ fz_drop_page(ctx, page); });
或者:
fz_context *ctx = ...;
fz_page *page = ...;
auto deleter = [ctx](fz_page *page){ fz_drop_page(ctx, page); };
std::unique_ptr<fz_page, decltype(deleter)> pagePtr(page, deleter);
直接将 std::unique_ptr
构造函数与删除器一起使用对于 lambda 表达式来说有点麻烦,因为您无法命名类型。但是您可以使用这样的模板推断类型:
template <typename T, typename D, typename ...Args>
std::unique_ptr<T,D> make_unique_with_deleter( D deleter, Args&&...args )
{
return std::unique_ptr<T,D>(
new T( std::forward<Args>(args)... ),
std::move( deleter ) );
}
这样,您可以直接在一个地方创建一个带有 lambda 删除器的 unique_ptr。这是一个例子:
int main()
{
const auto ctx = make_unique_with_deleter<fz_context>(
[]( fz_context * ctx ){ fz_drop_context( ctx ); },
nullptr, nullptr, FZ_STORE_UNLIMITED );
const auto page = make_unique_with_deleter<fz_page>(
[ctx]( fz_page * pg ){ fz_drop_page( ctx.get(), pg ); },
ctx.get(), 1000000 );
// and so forth ...
}
我正在尝试使用 mupdf 创建一个程序(在 Qt 中),它允许我将文档的对象列为列表,并允许我 select 渲染/不渲染哪些对象。由于 Qt 是 C++,而且我对它更熟悉,所以我尝试将 mupdf 中定义的结构包装在 C++ 类.
现在我的问题是 - 你在 mupdf 中做的第一件事就是创建一个全局上下文,它被传递给所有东西,包括清理和删除结构的函数。
我熟悉创建一个重载的对象 operator()
,很像:
struct ContextDeleter
{
inline void operator()(fz_context* ctx)
{
fz_drop_context(ctx);
}
};
然后我可以交给 unique_ptr
-
std::unique_ptr<fz_context, ContextDeleter> ctxPtr;
我想不通的是如何用像这样的函数做同样的事情:
fz_drop_page(ctx, page);
即:
struct PageDeleter
{
inline void operator()(fz_context* ctx, fz_page* pg)
{
fz_drop_page(ctx, pg);
}
}
这显然是不正确的,但正是我正在努力实现的目标。
如何为 unique_ptr
创建包含 2 个参数(在本例中为必要的上下文指针)的删除器?有没有办法让 unique_ptr
知道删除页面的上下文指针(在本例中)?或者(我曾想过)我是否需要创建一些东西来包装 unique_ptr
以便我可以稍后以某种方式将其删除的上下文(还没有完全考虑清楚)。
我看过这里的例子:
How do I use a custom deleter with a std::unique_ptr member?
和
Wrapping of C-code with a unique_ptr and custom deleter
但我不知道如何让它们在我的情况下工作。
将 fz_context *
存储在删除器中,并将该删除器的实例传递给包含 fz_page *
unique_ptr
struct PageDeleter
{
explicit PageDeleter(fz_context *ctx)
: ctx(ctx)
{}
void operator()(fz_page* page) const
{
fz_drop_page(ctx, page);
}
fz_context *ctx;
};
将unique_ptr
构造为
fz_context *ctx = // get the fz_context
fz_page *page = // get the fz_page
PageDeleter page_del(ctx);
std::unique_ptr<fz_page, PageDeleter> pagePtr(page, page_del);
为方便起见,您可以将所有这些包装在一个 make_unique_fz_page
函数中。
尝试使用捕获 fz_context*
值的 lambda,而不是将其存储在自定义删除器中:
fz_context *ctx = ...;
fz_page *page = ...;
std::unique_ptr<fz_page, std::function<void(fz_page*)>> pagePtr(page, [ctx](fz_page *page){ fz_drop_page(ctx, page); });
或者:
fz_context *ctx = ...;
fz_page *page = ...;
auto deleter = [ctx](fz_page *page){ fz_drop_page(ctx, page); };
std::unique_ptr<fz_page, decltype(deleter)> pagePtr(page, deleter);
直接将 std::unique_ptr
构造函数与删除器一起使用对于 lambda 表达式来说有点麻烦,因为您无法命名类型。但是您可以使用这样的模板推断类型:
template <typename T, typename D, typename ...Args>
std::unique_ptr<T,D> make_unique_with_deleter( D deleter, Args&&...args )
{
return std::unique_ptr<T,D>(
new T( std::forward<Args>(args)... ),
std::move( deleter ) );
}
这样,您可以直接在一个地方创建一个带有 lambda 删除器的 unique_ptr。这是一个例子:
int main()
{
const auto ctx = make_unique_with_deleter<fz_context>(
[]( fz_context * ctx ){ fz_drop_context( ctx ); },
nullptr, nullptr, FZ_STORE_UNLIMITED );
const auto page = make_unique_with_deleter<fz_page>(
[ctx]( fz_page * pg ){ fz_drop_page( ctx.get(), pg ); },
ctx.get(), 1000000 );
// and so forth ...
}