24

C++ 11 では、shared_ptr非ポインター リソースを制御するために使用できますか?


unique_ptr非ポインタ リソースの管理に使用できます。これは、以下を提供するカスタム削除クラスを実装することによって行われます。

  1. A typedef {TYPE} pointer;where{TYPE}は非ポインター リソース タイプです
  2. operator()(pointer)制御されたリソースを解放します

...そしてunique_ptr、2 番目のテンプレート パラメータとしてカスタム デリータを使用して a をインスタンス化します。

たとえば、Windows では、サービス コントロール ハンドルunique_ptrを管理するを作成できます。このハンドル タイプは、 を呼び出すことによって解放されるのではなく、 を呼び出すことによって解放されます。これを行うサンプルコードは次のとおりです。deleteCloseServiceHandle()

カスタム・デリーター

struct SvcHandleDeleter
{
    typedef SC_HANDLE pointer;
    SvcHandleDeleter() {};

    template<class Other> SvcHandleDeleter(const Other&) {};

    void operator()(pointer h) const
    {
        CloseServiceHandle(h);
    }
};


typedef std::unique_ptr<SC_HANDLE,SvcHandleDeleter> unique_sch;

インスタンス化

unique_sch scm(::OpenSCManagerA(0, 0, SC_MANAGER_ALL_ACCESS));

shared_ptrポインタ以外のリソースを制御するために使用することは可能ですか?

ドキュメントによると、カスタムの削除クラスを提供する手段を提供するshared_ptrコンストラクターのオーバーロードがありますが、ポインターでもポインターのラッパーでもないリソースタイプを受け入れるコンストラクターはありません。

これはどのように行うことができますか?

4

4 に答える 4

15

悲しいことに、shared_ptrでは型消去が必要なため、現在のインターフェイスでは目的を正確に達成することができません。unique_ptr実際の「ポインター」タイプを描画できる場所から、実際のデリータタイプに関する静的情報を持っているため、なんとかそれを行うことができます。の場合、タイプ消去プロセスで削除タイプが失われます (これが、テンプレートshared_ptrで指定できない理由です)。shared_ptr

unique_ptrまた、のような変換コンストラクターを提供しないことにも注意してくださいshared_ptr(例: template<class Y> shared_ptr(Y* p))。必ずしも実際のポインター型であるとは限らないためpointer、受け入れることができるものを制限することはできません (SFINAE withstd::is_convertible_toまたはそのようなものを使用することを除いて... しかし、私は脱線します)。

さて、明白な回避策の 1 つはnew、リソース ハンドルを単純化することです。:/

std::shared_ptr<SC_HANDLE> sp(new SC_HANDLE(::OpenSCManagerA(0, 0, SC_MANAGER_ALL_ACCESS)),
    [](SC_HANDLE* p){ ::CloseServiceHandle(*p); delete p; });
于 2012-07-25T14:52:02.817 に答える
5

さて、 shared_ptr は、ポインタへの最後の参照が解放されるとすぐに、ポイントされたオブジェクトのデストラクタを呼び出し、クラスに含まれるものは何でも解放できます。おそらく次のようなクラスを作成してください:

struct SvcHandle
{
  typedef SC_HANDLE pointer;
  SvcHandle()
  :M_handle(::OpenSCManagerA(0, 0, SC_MANAGER_ALL_ACCESS))
  { }

  ~SvcHandle()
  {
      CloseServiceHandle(M_handle);
  }
private:
  pointer M_handle;
};

次に、新しい SvcHandle で共有ポインターを作成します。ハンドルのライフタイム管理は、最高の状態で shared_ptr - RAII と一緒に行われます。

于 2012-07-25T14:42:52.773 に答える
1

これはどう?

auto scm = make_shared<unique_sch>(::OpenSCManagerA(0, 0, SC_MANAGER_ALL_ACCESS));

unique_schは、質問で言及したクラスです。リソースへの共有ポインタとして scm を使用します。必要に応じて逆参照するのは良いことではありませんが、可能かどうか尋ねました。

しかし、それはまだポインターを使用しています。ドキュメントに見られるように、unique_ptrクラスはポインタークラスをコンストラクター パラメーターとして受け取りますが、これは実際には何でもかまいません。 ただし、 shared_ptrはテンプレート パラメーターとして型を取り、それをコンストラクターの型へのポインターに強制的に変換します。

template< class Y, class Deleter > shared_ptr( Y* ptr, Deleter d );

shared_ptrクラスはそのリソースがポインターであると想定しているため、ポインター以外のリソースを管理するために直接使用することはできないと言っても過言ではありません。

于 2012-07-25T14:52:53.130 に答える
0

いいえと思います。標準では、shared_ptrにそのようなコンストラクターを提供し、他のコンストラクターは提供しません。

// 20.7.2.2.1, constructors:
constexpr shared_ptr() noexcept;
template<class Y> explicit shared_ptr(Y* p);
template<class Y, class D> shared_ptr(Y* p, D d);
template<class Y, class D, class A> shared_ptr(Y* p, D d, A a);
template <class D> shared_ptr(nullptr_t p, D d)
template <class D, class A> shared_ptr(nullptr_t p, D d, A a)
template<class Y> shared_ptr(const shared_ptr<Y>& r, T *p) noexcept;
shared_ptr(const shared_ptr& r) noexcept;
template<class Y> shared_ptr(const shared_ptr<Y>& r) noexcept;
shared_ptr(shared_ptr&& r) noexcept;
template<class Y> shared_ptr(shared_ptr<Y>&& r) noexcept;
template<class Y> explicit shared_ptr(const weak_ptr<Y>& r);
template<class Y> shared_ptr(auto_ptr<Y>&& r);
template <class Y, class D> shared_ptr(unique_ptr<Y, D>&& r);
constexpr shared_ptr(nullptr_t) : shared_ptr() { }

そして、たとえば、どのように実行したいか(unique_ptrの場合)

pointer release() noexcept;

1事後条件:get()==nullptr。2戻り値:リリースの呼び出しの開始時にget()の値がありました。

ポインタリソースがありませんか?あなたは言語をハックしようとします。それは常に悪い考えです。

于 2012-07-25T14:47:02.547 に答える