使用Boost的共享_ptr管理C类型生命周期?
-
25-10-2019 - |
题
我有一个类似的问题 如何使用Boost Library智能指针来管理对象寿命? 但是,就我而言,“对象”根本不是C ++对象,而是从C API返回/脱离的不透明类型。该类型没有指针语义,即没有指示。但是,它作为参数传递给C API中的其他函数。该类型还具有确切的 close
为了清理内部资源,必须调用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
没有指针语义,用法 managed
有点笨拙。
我想做的就是拥有像 managed_type
那类似于 shared_ptr
, 并且正在寻找不需要我写全部的想法。
编辑: 我在示例中纠正了我的原始搞砸。传统API按值而不是指针采用不透明的类型。
解决方案
您可以将Boost Smart指针与Pimpl Idom一起使用:
class shared_opaque_legacy_type_t {
struct impl {
opaque_legacy_type_t t;
impl(...) { XXOpen(..., t); }
~impl(...) { XXClose(t); }
}
boost::shared_ptr<impl> _impl;
public:
shared_opaque_lagacy_type_t(...) : _impl(new impl(...)) {}
opaque_legacy_type_t* get() {
return _impl->t;
}
};
shared_opaque_legacy_type_t x(...);
XXdoSomethingWithResource(x.get(), ...);
缺点是您仍然可以打电话 XXclose(x.get())
并使您的对象无效。
更新: : 解决它。 :-)
其他提示
由于所有旧式API都采用了不透明类型的指针,因此您可以直接使用共享指针。关键是要让您不声明堆栈上的原始结构,而是通过 new
:
int main () {
std::shared_ptr<opaque_legacy_type_t> x(new opaque_legacy_type_t,
[](opaqeue_legacy_type_t* p) { XXClose(p); delete p; });
XXopen(..., x.get());
XXdoSomethingWithResource(x.get(), ...);
}
编辑: :如果某些API按值而不是指针采用不透明的类型,请传递注射的指针。
int main () {
std::shared_ptr<opaque_legacy_type_t> x(new opaque_legacy_type_t,
[](opaqeue_legacy_type_t* p) { XXClose(*p); delete p; });
XXopen(..., x.get());
XXdoSomethingWithResource(*x, ...);
}
您可以编写一个包装器,将其与Boost一起使用 open()
在CTOR和 close()
在DTOR中。
我投票支持罗布的回答,只是使用 shared_ptr
没有包装器,但是如果您真的想避免动态分配,这是一个简单的小例子,说明了如何做到这一点。
这是一个直接固定手柄并且没有分配的模板。您通过构造函数来创建不透明类型的对象,并在需要破坏该类型时要调用的eleter。它是可移动且不可拷贝的,因此现在需要共享参考计数。它实现隐式转换操作员,因此您可以在使用固定类型的值的地方使用它。
template<typename T,typename D>
class opaque_type_handle {
T handle;
D deleter;
bool needs_delete;
public:
template<typename F>
opaque_type_handle(F f,D d) : handle(f()), deleter(d), needs_delete(true) {}
opaque_type_handle(opaque_type_handle const &) = delete;
opaque_type_handle &operator=(opaque_type_handle const &) = delete;
opaque_type_handle(opaque_type_handle &&rhs) : handle(rhs.handle),deleter(rhs.deleter),needs_delete(true) {
rhs.needs_delete = false;
}
opaque_type_handle &operator=(opaque_type_handle &&rhs) {
handle = rhs.handle;
deleter = rhs.deleter;
needs_delete = true;
rhs.needs_delete = false;
returh *this;
}
~opaque_type_handle() {
if(needs_delete) {
deleter(handle);
}
}
operator T&() { return handle; }
operator T() const { return handle; }
};
像这样使用:
// wrap up the code for creating an opaque_legacy_type_t handle
typedef opaque_type_handle<opaque_legacy_type_t,decltype(&XXclose)> legacy_handle;
legacy_handle make_legacy_handle(...) {
return legacy_handle(
[](){
opaque_legacy_type_t tmp;
XXopen(..., &tmp);
return tmp;
},
&XXclose
);
}
legacy_handle x = make_legacy_handle(...);
XXdoSomethingWithResource(x,...);