配列へのshared_ptr:使用する必要がありますか?


172

に関する小さなクエリshared_ptr

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

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

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


2
FWIT、あなただけの使用を検討することもできますstd::vector。コピーを作成しないように、参照を使用して配列を渡すように注意する必要があります。データにアクセスするための構文は、shared_ptrよりもきれいで、サイズ変更は非常に簡単です。そして、あなたが望むなら、あなたはすべてのSTLの良さを手に入れます。
Nicu Stiurca、2012年

6
配列のサイズがコンパイル時に決定される場合は、の使用も検討してくださいstd::array。これはraw配列とほとんど同じですが、ほとんどのライブラリコンポーネントで使用できる適切なセマンティクスを備えています。特に、そのタイプのオブジェクトはdelete、ではなくで破棄されdelete[]ます。とは異なりvector、データはオブジェクトに直接格納されるため、余分な割り当てはありません。
celtschk 2015

回答:


268

C ++ 17shared_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);

必要: Y完全なタイプでなければならない。式はdelete[] p、時にT配列型である、またはdelete pとき、T配列型ではなく、行動を明確に定義されなければならない、と例外をスローしてはなりません。
...
備考:ときTアレイ型で発現がない限り、このコンストラクタは、オーバーロード解決に参加してはならないdelete[] pだけでなく、形成されており、いずれかTであるU[N]Y(*)[N]に変換されT*、またはTであり U[]且つY(*)[]に変換可能T*。...

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

using element_type = remove_extent_t<T>;

配列要素には、 operator[]

  element_type& operator[](ptrdiff_t i) const;

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


C ++ 17の前にshared_ptr可能性がない動的に割り当てられたアレイを管理するために使用すること。デフォルトでshared_ptrdelete、管理オブジェクトへの参照がなくなると、は管理オブジェクトを呼び出します。ただし、を使用して割り当てる場合は、ではなく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、配列型を部分的に特殊化しているため、このタスクにはが適しています。

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

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

上記にリストされたものの別のC ++ 17以前の代替は、ライブラリの基本技術仕様によって提供されましたshared_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);

必要Y完全なタイプである必要があります。表現delete[] pT配列型である、またはdelete pとき、T配列型ではありませんが、整形式でなければならない、明確に定義された振る舞いを持たなければならない、と例外をスローしてはなりません。ときTであるU[N]Y(*)[N]に変換しなければなりませんT*。ときTであるU[]Y(*)[]に変換しなければなりませんT*。それ以外の場合は、Y*に変換できT*ます。


9
+1、備考:ブーストもありshared-arrayます。
jogojapan 2012年

5
@ tshah06 shared_ptr::getは、管理対象オブジェクトへのポインタを返します。そのため、次のように使用できますsp.get()[0] = 1; ... sp.get()[9] = 10;
Praetorian

55
ALT:en.cppreference.com/w/cpp/memory/default_deletestd::shared_ptr<int> sp( new int[10], std::default_delete<int[]>() );参照
yohjp

2
@Jeremyコンパイル時にサイズがわかっている場合は、そのためのクラスを作成する必要はなく、std::shared_ptr<std::array<int,N>>十分です。
Praetorian 2013年

13
なぜunique_ptrその部分的な専門化を取得するのに取得shared_ptrしないのですか?
2014年

28

あなたが使用できるかもしれない、おそらくもっと簡単な代替案はshared_ptr<vector<int>>です。


5
はい、そうです。または、ベクトルは配列のスーパーセットです-ベクトルは同じメモリ内表現(およびメタデータ)を持っていますが、サイズ変更可能です。配列が必要だがベクトルを使用できない状況は実際にはありません。
Timmmm 2014

2
ここでの違いは、ベクトルサイズが静的であり、データへのアクセスが二重の間接参照で行われることです。パフォーマンスが重要な問題ではない場合、これは機能します。それ以外の場合は、アレイの共有に独自の理由がある可能性があります。
Emilio Garavaglia

4
次に、おそらく使用できますshared_ptr<array<int, 6>>
Timmmm

10
他の違いは、生の配列よりも少し大きくて遅いということです。一般的にはそれほど問題ではありませんが、1 == 1.1であるように見せかけましょう。
Andrew

2
配列内のデータのソースが、ベクトルへの変換が扱いにくいまたは不必要であることを意味する場合があります。カメラからフレームを取得するときなど。(または、とにかく、それは私の理解です)
Narfanator '30
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.