使用boost的shared_ptr管理C类型生命周期?

时间:2012-02-15 20:12:59

标签: c++ boost shared-ptr object-lifetime

我有一个类似于How to manage object life time using Boost library smart pointers?的问题,但在我的情况下,“对象”根本不是C ++对象,而是从C API返回/传递的opaque类型。该类型没有指针语义,即没有解除引用;但是,它作为参数传递给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采用opaque类型而不是指针。

4 个答案:

答案 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,...);