126

比較、長所、短所、およびいつ使用するか?

これはガベージ コレクション スレッドから派生したもので、単純な答えだと思っていたものが、特定のスマート ポインターの実装に関する多くのコメントを生成したため、新しい投稿を開始する価値があるように思われました。

最終的に問題となるのは、C++ でのスマート ポインターのさまざまな実装と、それらをどのように比較するかということです。単純な長所と短所、または例外と、そうでなければうまくいくと思われるものへの落とし穴です。

私が使用した、または少なくとも大まかに説明して、以下の回答として使用することを検討したいくつかの実装と、100%正確ではない可能性があるそれらの相違点と類似点の理解を投稿しました。

目標は、いくつかの新しいオブジェクトとライブラリについて学習するか、すでに広く使用されている既存の実装の使用法と理解を修正し、他の人にとって適切なリファレンスになることです。

4

3 に答える 3

234

C ++ 03

std::auto_ptr-おそらく、最初のドラフト症候群に苦しんでいたオリジナルの1つは、限られたガベージコレクション施設しか提供していませんでした。最初の欠点はdelete、破壊を要求するため、配列に割り当てられたオブジェクトを保持できないことです(new[])。ポインタの所有権を取得するため、2つの自動ポインタに同じオブジェクトが含まれることはありません。割り当てにより、所有権が譲渡され、右辺値の自動ポインターがnullポインターにリセットされます。これはおそらく最悪の欠点につながります。前述のコピーができないため、STLコンテナ内では使用できません。ユースケースの最後の打撃は、C++の次の標準で非推奨になる予定です。

std::auto_ptr_refstd::auto_ptr-これはスマートポインタではなく、実際には、特定の状況でコピーと割り当てを可能にするために組み合わせて使用​​される設計の詳細です。具体的には、所有権を譲渡するための移動コンストラクターとしても知られるColvin-Gibbonsトリックを使用して、非定数std::auto_ptr左辺値に変換するために使用できます。

それどころかstd::auto_ptr、自動ガベージコレクションの汎用スマートポインタとして使用することを意図したものではなかったのかもしれません。私の限られた理解と仮定のほとんどは、ハーブサッターのauto_ptrの効果的な使用に基づいており、常に最適化された方法であるとは限りませんが、定期的に使用しています。


C ++ 11

std::unique_ptr-これは私たちの友人であり、配列の操作、プライベートコピーコンストラクターによる左辺値の保護、STLコンテナーやアルゴリズムでの使用などstd::auto_ptrの弱点を修正するための主要な改善点を除いて、非常によく似ています。パフォーマンスのオーバーヘッドであるためメモリーフットプリントは限られています。これは、生のポインターを置き換える、またはおそらくより適切に所有していると説明するための理想的な候補です。「一意」とは、前のポインタと同じように、ポインタの所有者が1人だけであることを意味します。std::auto_ptrstd::auto_ptr

std::shared_ptr-これはTR1に基づいていると思いますboost::shared_ptrが、エイリアシングとポインタ演算も含めるように改善されています。つまり、動的に割り当てられたオブジェクトの周りに参照カウントされたスマートポインターをラップします。「共有」は、最後の共有ポインターの最後の参照がスコープ外になると、ポインターが複数の共有ポインターによって所有される可能性があることを意味するため、オブジェクトは適切に削除されます。これらもスレッドセーフであり、ほとんどの場合、不完全な型を処理できます。デフォルトのアロケータを使用して、1つのヒープ割り当てでstd::make_shared効率的にを構築するために使用できます。std::shared_ptr

std::weak_ptr-同様にTR1とに基づいていboost::weak_ptrます。これは、が所有するオブジェクトへの参照であるため、参照数がゼロstd::shared_ptrになってもオブジェクトの削除を妨げることはありません。std::shared_ptr生のポインタにアクセスするには、最初にstd::shared_ptrを呼び出すことによってアクセスする必要があります。これは、所有されているポインタの有効期限が切れてすでに破棄されている場合はlock空を返します。std::shared_ptrこれは主に、複数のスマートポインターを使用するときに、参照カウントが無期限にハングするのを防ぐのに役立ちます。


ブースト

boost::shared_ptr-おそらく、最も多様なシナリオ(STL、PIMPL、RAIIなど)で使用するのが最も簡単です。これは、共有参照されたカウントされたスマートポインターです。いくつかの状況でパフォーマンスとオーバーヘッドについていくつかの不満を聞いたことがありますが、議論が何であったかを思い出せないので、それらを無視したに違いありません。どうやらそれは保留中の標準C++オブジェクトになるのに十分人気があり、スマートポインタに関する標準を超える欠点は思い浮かびません。

boost::weak_ptr-の前の説明と同様std::weak_ptrに、この実装に基づいて、これにより、を所有していない参照が可能になりますboost::shared_ptr。当然のことながら、「強力な」共有ポインタにアクセスするために呼び出しlock()、すでに破棄されている可能性があるため、有効であることを確認する必要があります。返された共有ポインタを保存しないように注意し、使い終わったらすぐにスコープから外してください。そうしないと、参照カウントがハングし、オブジェクトが破棄されない循環参照の問題に戻ります。

boost::scoped_ptr-これは、オーバーヘッドがほとんどない単純なスマートポインタークラスであり、おそらくboost::shared_ptr使用可能な場合よりもパフォーマンスが向上するように設計されています。std::auto_ptrこれは、STLコンテナの要素として、または同じオブジェクトへの複数のポインタで安全に使用できないという事実に特に匹敵します。

boost::intrusive_ptr-私はこれを使用したことがありませんが、私の理解から、独自のスマートポインタ互換クラスを作成するときに使用するように設計されています。自分でカウントする参照を実装する必要があります。クラスを汎用にする場合は、いくつかのメソッドも実装する必要があります。さらに、独自のスレッドセーフを実装する必要があります。プラス面としては、これにより、必要な「スマートさ」を正確にどれだけ、またはどれだけ少なくするかを選択するための最もカスタムな方法が得られるでしょう。通常、オブジェクトごとに単一のヒープ割り当てを行うことができるためintrusive_ptr、より効率的です。(Arvidに感謝)shared_ptr

boost::shared_array-これはboost::shared_ptrアレイ用です。基本的new []に、、、operator[]およびもちろんdelete []ベイクインされます。これはSTLコンテナーで使用でき、私が知る限り、これらでboost:shared_ptrは使用できませんが、すべてが実行されますboost::weak_ptr。ただし、代わりにaを使用しboost::shared_ptr<std::vector<>>て同様の機能を使用boost::weak_ptrし、参照に使用する機能を取り戻すこともできます。

boost::scoped_array-これはboost::scoped_ptrアレイ用です。必要なすべてのアレイと同様にboost::shared_array、優れた機能が組み込まれています。これはコピーできないため、STLコンテナでは使用できません。私はあなたがこれを使いたいと思うほとんどどこでもあなたがたぶん使うことができるのを見つけましたstd::vector。どちらが実際に高速であるか、オーバーヘッドが少ないかを判断したことはありませんが、このスコープ配列はSTLベクトルよりもはるかに複雑ではないようです。スタックに割り当てを保持したい場合は、boost::array代わりに検討してください。


Qt

QPointer-Qt 4.0で導入された、これは「弱い」スマートポインターでありQObject、クラスと派生クラスでのみ機能します。Qtフレームワークではほとんどすべてであるため、実際には制限はありません。ただし、「強力な」ポインタを提供しないという制限があります。基になるオブジェクトが有効かどうかを確認isNull()できますが、特にマルチスレッド環境では、そのチェックに合格した直後にオブジェクトが破棄される可能性があります。Qtの人々は、これは非推奨だと私は信じています。

QSharedDataPointerboost::intrusive_ptr-これは、スレッドセーフが組み込まれているものの、潜在的に同等の「強力な」スマートポインターですが、サブクラス化によって実行できる参照カウントメソッド(refおよび)を含める必要があります。Qtの多くと同様に、オブジェクトは十分な継承を通じて最もよく使用され、すべてをサブクラス化することは意図された設計のようです。derefQSharedData

QExplicitlySharedDataPointerQSharedDataPointer-暗黙的にを呼び出さないことを除いて、非常に似ていますdetach()QSharedDataPointer参照カウントがゼロに低下した後、いつデタッチするかについての制御のわずかな増加は、まったく新しいオブジェクトの価値が特にないため、このバージョン2.0と呼びます。

QSharedPointer-アトミック参照カウント、スレッドセーフ、共有可能なポインター、カスタム削除(配列サポート)、スマートポインターが必要なすべてのように聞こえます。これは、私が主にQtのスマートポインターとして使用するものでboost:shared_ptrあり、Qtの多くのオブジェクトのように、おそらく大幅にオーバーヘッドが大きくなりますが、それに匹敵すると思います。

QWeakPointer-繰り返し発生するパターンを感じますか?同様にstd::weak_ptr、これは、オブジェクトが削除されない原因となる2つのスマートポインター間の参照が必要な場合boost::weak_ptrと組み合わせて使用​​されます。QSharedPointer

QScopedPointer-この名前も見覚えがあるはずですが、実際にboost::scoped_ptrは、Qtバージョンの共有ポインターや弱ポインタ​​ーとは異なります。これは、オーバーヘッドなしで単一の所有者のスマートポインターを提供するように機能し、QSharedPointer互換性、例外安全コード、および使用する可能性のあるすべてのものに適していstd::auto_ptrますboost::scoped_ptr

于 2011-02-17T08:44:16.110 に答える
5

ポリシーベースのスマートポインタを実装するLokiもあります。

多くのコンパイラによる多重継承に加えて、空のベース最適化のサポートが不十分であるという問題に対処する、ポリシーベースのスマートポインタに関するその他のリファレンス:

于 2011-09-02T23:42:51.443 に答える