我有一个类似于How to manage object life time using Boost library smart pointers?的问题,但在我的情况下,“对象”根本不是C ++对象,而是从C API返回/传递的opaque类型。该类型没有指针语义,即没有解除引用;但是,它作为参数传递给C API中的其他函数。该类型还有一个明确的close
API,必须调用它才能清理内部资源。
所以,我有一个类似于
的C APIopaque_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采用opaque类型而不是指针。
答案 0 :(得分:2)
由于所有遗留API都采用指向opaque类型的指针,因此您可以直接使用共享指针。关键是你不要在堆栈上声明原始结构,而是通过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按值而不是指针采用opaque类型,则传递解除引用的指针。
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, ...);
}
答案 1 :(得分:1)
您可以编写一个与boost一起使用的包装器,它将调用ctor中的open()
和dtor中的close()
。
答案 2 :(得分:1)
您可以将boost智能指针与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())
并使你的对象无效。
更新:修正了它。 : - )
答案 3 :(得分:0)
我投票支持Rob的答案,即只使用没有包装的shared_ptr
,但如果你真的想避免动态分配,那么这是一个简单的小例子。
这是一个直接保存句柄并且不进行分配的模板。您将构造函数传递给创建opaque类型对象的仿函数,以及在需要销毁类型时调用的删除器。它是可移动的和不可复制的,因此现在需要共享引用计数。它实现了隐式转换运算符,因此您可以在使用保持类型的值的地方使用它。
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,...);