191

に関するちょっとした質問shared_ptrです。

shared_ptr配列を指すことを使用することは良い習慣ですか? 例えば、

shared_ptr<int> sp(new int[10]);

そうでない場合、なぜですか?私がすでに認識している理由の 1 つは、 をインクリメント/デクリメントできないことshared_ptrです。したがって、配列への通常のポインターのようには使用できません。

4

2 に答える 2

297

C++17では、shared_ptr動的に割り当てられた配列を管理するために使用できます。この場合のshared_ptrテンプレート引数はT[N]またはでなければなりませんT[]。だからあなたは書くかもしれません

shared_ptr<int[]> sp(new int[10]);

n4659より、[util.smartptr.shared.const]

  template<class Y> explicit shared_ptr(Y* p);

Requires: Y完全な型でなければなりません。式が配列型のdelete[] p場合T、または が配列型でないdelete p場合、T式は明確に定義された動作をし、例外をスローしません。
...
備考:Tが配列型の場合、このコンストラクターは、式が整形式であり、 is および is に変換可能であるか、または is and is に変換可能でない限り、オーバーdelete[] pロードの 解決に参加TU[N]ません。...Y(*)[N]T*TU[]Y(*)[]T*

これをサポートするために、メンバー型element_typeは次のように定義されています。

using element_type = remove_extent_t<T>;

配列要素は次を使用してアクセスできますoperator[]

  element_type& operator[](ptrdiff_t i) const;

必要: get() != 0 && i >= 0 . Tの場合U[N]i < N。...
備考:が配列型でない場合T、このメンバー関数が宣言されているかどうかは不定です。関数が宣言されている場合、その戻り値の型が何であるかは指定されていませんが、関数の宣言 (必ずしも定義である必要はありません) が適切に形成されている必要があります。


C++17 より前では、動的に割り当てられた配列の管理には使用shared_ptrできませんでした。デフォルトでは、管理対象オブジェクトへの参照がなくなると、管理対象オブジェクトshared_ptrが呼び出されます。deleteただし、 using を使用して割り当てる場合は、 ではなくnew[]を呼び出して、リソースを解放する必要があります。delete[]delete

配列で正しく使用するshared_ptrには、カスタムのデリータを提供する必要があります。

template< typename T >
struct array_deleter
{
  void operator ()( T const * p)
  { 
    delete[] p; 
  }
};

次のように shared_ptr を作成します。

std::shared_ptr<int> sp(new int[10], array_deleter<int>());

管理オブジェクトを破棄するときshared_ptrに正しく呼び出されるようになりました。delete[]

上記のカスタム デリーターは、

  • 配列型のstd::default_delete部分的な特殊化

    std::shared_ptr<int> sp(new int[10], std::default_delete<int[]>());
    
  • ラムダ式

    std::shared_ptr<int> sp(new int[10], [](int *p) { delete[] p; });
    

また、管理対象オブジェクトの共有権限が実際に必要でない限り、unique_ptr配列型の部分的な特殊化があるため、このタスクには a の方が適しています。

std::unique_ptr<int[]> up(new int[10]); // this will correctly call delete[]

Library Fundamentals の C++ 拡張機能によって導入された変更

上記にリストされているものに代わる C++17 以前の別の代替手段がLibrary Fundamentals Technical Specificationshared_ptrによって提供されました。これは、オブジェクトの配列を所有している場合にすぐに使用できるように拡張されています。shared_ptrこの TS に予定されている変更の現在のドラフトは、N4082にあります。これらの変更はstd::experimental名前空間を介してアクセスでき、<experimental/memory>ヘッダーに含まれます。shared_ptr配列のサポートに関連するいくつかの変更は次のとおりです。

— メンバー タイプの定義がelement_type変更されました

typedef T element_type;

 typedef typename remove_extent<T>::type element_type;

— メンバーoperator[]が追加されています

 element_type& operator[](ptrdiff_t i) const noexcept;

unique_ptr—配列の部分的な特殊化とは異なり、shared_ptr<T[]>とのshared_ptr<T[N]>両方が有効であり、どちらもdelete[]オブジェクトのマネージド配列で呼び出されます。

 template<class Y> explicit shared_ptr(Y* p);

Requires :Y完全な型でなければなりません。が配列型の場合、またはが配列型でないdelete[] p場合の式は、整形式であり、動作が明確に定義されていなければならず、例外をスローしてはなりません。の場合、に変換可能です。の場合、に変換可能です。それ以外の場合は、に変換できるものとします。Tdelete pTTU[N]Y(*)[N]T*TU[]Y(*)[]T*Y*T*

于 2012-10-25T05:21:40.800 に答える
32

使用できる可能性のあるより簡単な代替手段は ですshared_ptr<vector<int>>

于 2013-10-03T13:03:03.437 に答える