我有一个类似的问题 如何使用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,...);
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top