2

Boost ライブラリのスマート ポインタを使用してオブジェクトの有効期間を管理する方法と同様の質問があります。しかし、私の場合、「オブジェクト」は 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 は、不透明型をポインターではなく値で受け取ります。

4

4 に答える 4

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, ...);
}
于 2012-02-15T20:29:59.903 に答える
1

ブースト スマート ポインターを 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())、オブジェクトを呼び出して無効にすることができることです。

更新:修正しました。:-)

于 2012-02-15T20:26:31.660 に答える
1

open()ctorとdtorで を呼び出す boost で使用するラッパーを作成できますclose()

于 2012-02-15T20:15:39.020 に答える
0

ラッパーなしでa を使用するだけのRobの回答に投票しましたshared_ptrが、動的割り当てを本当に避けたい場合は、その方法の簡単な例を次に示します。

ハンドルを直接保持し、割り当てを行わないテンプレートです。不透明な型のオブジェクトを作成するファンクタと、型を破棄する必要があるときに呼び出すデリータをコンストラクタに渡します。移動可能でコピーできないため、共有参照カウントが必要になりました。暗黙的な変換演算子を実装しているため、保持された型の値を使用する場所で使用できます。

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,...);
于 2012-02-16T16:50:02.423 に答える