使用boost的shared_ptr管理C类型生命周期?
我有一个类似于 如何管理对象的问题使用 Boost 库智能指针的生命周期?但是,就我而言,“对象”根本不是 C++ 对象,而是从 C API 返回/传递的不透明类型。该类型没有指针语义,即没有解引用;然而,它作为参数传递给 C API 中的其他函数。该类型还有一个明确的 close
API,必须调用该 API 才能清理内部资源。
因此,我有一个 C API,它类似于出于
opaque_legacy_type_t x;
XXopen(..., &x); // allocates/opens resource and fills out 'x' to be used later
XXdoSomethingWithResource(x, ...); // do something with resources related to 'x'
...more actions...
XXclose(x); // closes and cleans up resources related to 'x'
各种原因,在我的 C++ 代码中,我想管理 opaque_legacy_type_t 的“实例”,就像管理堆分配的对象实例一样,即具有与 boost::shared_ptr
。似乎 shared_ptr
提供了足够的功能,我可以通过这样做来管理调用 XXclose
:
opaque_legacy_type_t x;
XXopen(..., &x);
boost::shared_ptr<opaque_legacy_type_t> managed(x, XXclose);
但是,由于 opaque_legacy_type_t
没有指针语义,因此用法托管
有点笨拙。
我想做的是拥有类似于 shared_ptr
的 management_type
之类的东西,并且正在寻找不需要我全部编写的想法。
编辑: 我纠正了示例中最初的错误。旧版 API 通过值而不是指针获取不透明类型。
I have a question similar to How to manage object life time using Boost library smart pointers? but, in my case, the "object" isn't a C++ object at all, but an opaque type returned/passed out from a C API. The type does not have pointer semantics, i.e., there is no dereferencing; it is, however, passed as an argument to other functions in the C API. The type also has a definitive close
API which must be called in order to clean up internal resources.
So, I have a C API that's something along the lines of
opaque_legacy_type_t x;
XXopen(..., &x); // allocates/opens resource and fills out 'x' to be used later
XXdoSomethingWithResource(x, ...); // do something with resources related to 'x'
...more actions...
XXclose(x); // closes and cleans up resources related to 'x'
For various reasons, in my C++ code I would like to manage "instances" of opaque_legacy_type_t much like I would manage heap-allocated object instances, i.e. with similar sharing semantics as boost::shared_ptr<>
. It seems that shared_ptr
offers enough that I can manage calling XXclose
by doing this:
opaque_legacy_type_t x;
XXopen(..., &x);
boost::shared_ptr<opaque_legacy_type_t> managed(x, XXclose);
But, since opaque_legacy_type_t
doesn't have pointer semantics, the usage of managed
is a bit clumsy.
What I'd like to do is have something like a managed_type
that is similar to shared_ptr
, and am looking for ideas that don't require me to write it all.
EDIT: I corrected my original screw-up in the example. The legacy API takes the opaque type by value rather than by pointer.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
由于所有旧版 API 都采用指向不透明类型的指针,因此您可以直接使用共享指针。关键是您不要在堆栈上声明原始结构,而是通过 new 分配它:
EDIT: If some API take the opaque type by value instead of pointer, then pass the dereferenced pointer.
Since all of the legacy API take a pointer to the opaque type, you could use shared pointers directly. The key is for you to not declare the original structure on the stack, but rather allocate it via
new
:EDIT: If some API take the opaque type by value instead of pointer, then pass the dereferenced pointer.
您可以将 boost 智能指针与 pimpl idom 一起使用:
缺点是您仍然可以调用 XXclose(x.get()) 并使您的对象无效。
更新:修复了它。 :-)
You could use boost smart pointers together with the pimpl idom:
The drawback is that you could still call
XXclose(x.get())
and invalidate your object.UPDATE: Fixed it. :-)
您可以编写一个与 boost 一起使用的包装器,它将调用 ctor 中的
open()
和 dtor 中的close()
。You could write a wrapper to use with boost that will call the
open()
in the ctor and theclose()
in the dtor.我投票支持 Rob 的答案,该答案仅使用没有包装器的
shared_ptr
,但如果您确实想避免动态分配,这里有一个简单的小示例说明如何做到这一点。它是一个直接持有句柄并且不进行分配的模板。您向构造函数传递一个用于创建不透明类型的对象的函子,以及一个在需要销毁该类型时调用的删除器。它是可移动且不可复制的,因此现在需要共享引用计数。它实现了隐式转换运算符,因此您可以在使用保留类型的值的地方使用它。
像这样使用它:
I voted for Rob's answer that just uses a
shared_ptr
with no wrapper, but if you really want to avoid dynamic allocation here's a simple little example of how to do that.It's a template that directly holds the handle and does no allocation. You pass the constructor a functor that creates an object of the opaque type, and a deleter to call when the type needs to be destroyed. It's movable and non-copyable so now shared reference count is needed. It implements implicit conversion operators so you can use it where you'd use a value of the held type.
Use it like so: