正しく理解していれば、weak_ptr
は管理対象オブジェクトの参照カウントを増加させないため、所有権を表しません。オブジェクトにアクセスするだけで、その有効期間は他の誰かが管理します。したがって、weak_ptr
をunique_ptr
から構築できないのはなぜかはわかりませんが、shared_ptr
のみです。
誰かがこれを簡単に説明できますか?
lock()
を使用してstd::weak_ptr
に変換しない限り、std::shared_ptr
は使用できません。標準があなたの提案を許可した場合、それはあなたがそれを使用するためにstd :: weak_ptrを一意に変換する必要があることを意味し、一意性に違反する(またはstd::shared_ptr
を再発明する)
説明のために、次の2つのコードを見てください。
std::shared_ptr<int> shared = std::make_shared<int>(10);
std::weak_ptr<int> weak(shared);
{
*(weak.lock()) = 20; //OK, the temporary shared_ptr will be destroyed but the pointee-integer still has shared to keep it alive
}
あなたの提案で:
std::unique_ptr<int> unique = std::make_unique<int>(10);
std::weak_ptr<int> weak(unique);
{
*(weak.lock()) = 20; //not OK. the temporary unique_ptr will be destroyed but unique still points at it!
}
そうは言っても、unique_ptr
は1つだけで、weak_ptr
を間接参照することもできます(別のunique_ptr
を作成しなくても)、問題はありません。しかし、1つの参照を持つunique_ptr
とshared_ptr
の違いは何ですか?または、通常のunique_ptr
とget
を使用して取得するCポインターの違いは何ですか?
weak_ptr
は「一般的な非所有リソース」ではなく、非常に具体的な仕事を持っています-weak_ptr
の主な目標は、メモリリークを引き起こすshared_ptr
の循環ポインティングを防ぐことです。それ以外のことは、プレーンunique_ptr
およびshared_ptr
で行う必要があります。
考えてみると、weak_ptr
はオブジェクト自体以外のものを参照する必要があります。これは、オブジェクトが存在しなくなる可能性があり(オブジェクトへの強力なポインタがなくなると)、weak_ptr
がオブジェクトがもはや存在しないという情報を含む何かを参照する必要があるためです。
shared_ptr
の場合、それは参照カウントを含むものです。しかし、unique_ptr
を使用すると、参照カウントが存在しないため、参照カウントを含むものが存在しないため、オブジェクトがなくなっても存在し続けるものはありません。したがって、weak_ptr
を参照するものは何もありません。
そのようなweak_ptr
を使用する正しい方法もありません。それを使用するには、使用中にオブジェクトが破壊されなかったことを保証する何らかの方法が必要です。 shared_ptr
を使用すると簡単です。これがshared_ptr
の機能です。しかし、どのようにunique_ptr
でそれを行うのですか?明らかにそれらのうちの2つを使用することはできません。他の何かがすでにオブジェクトを所有している必要があります。
shared_ptr
には基本的に2つの部分があります。
参照カウントがゼロに下がると、オブジェクト(#1)は削除されます。
ここで、weak_ptr
はオブジェクトがまだ存在するかどうかを知る必要があります。これを行うには、参照カウントオブジェクト(#2)がゼロでない場合、参照カウントをインクリメントすることにより、オブジェクトのshared_ptr
を作成できる必要があります。カウントがゼロの場合、空のshared_ptr
を返します。
次に、参照カウントオブジェクト(#2)をいつ削除できるかを検討しますか? shared_ptr
OR weak_ptr
オブジェクトが参照するまで待つ必要があります。このため、参照カウントオブジェクトはtwo参照を保持しますcounts、astrongrefおよびaweakref。参照カウントオブジェクトは、両方のカウントがゼロの場合にのみ削除されます。メモリは、すべての弱い参照がなくなった後にのみ解放できます(これは、make_shared
による 隠れた不利益を意味します )。
tl; dr;weak_ptr
は、shared_ptr
の一部であるweak reference countに依存し、weak_ptr
は存在できませんshared_ptr
なし。
概念的には、weak_ptrがアクセスのみを提供し、unique_ptrがライフタイムを制御する実装を妨げるものはありません。ただし、それには問題があります。
unique_ptr
は、最初に参照カウントを使用しません。弱参照を管理するための管理構造を追加することは可能ですが、追加の動的割り当てが必要です。 unique_ptr
は、生のポインターに対する実行時オーバーヘッドを回避することになっているため、そのオーバーヘッドは許容されません。weak_ptr
によって参照されるオブジェクトを使用するには、そのオブジェクトから「実際の」参照を抽出する必要があります。これは、最初にポインターの有効期限が切れていないことを検証してから、この実際の参照(shared_ptr
この場合)。これは、一意に所有されることになっているオブジェクトへの2番目の参照が突然あることを意味します。これはエラーのレシピです。これは、ポインティッドの破壊を一時的に遅らせるだけの混合ハーフストロングポインタを返すことでは修正できません。ポインティティを保存することもでき、unique_ptr
の背後にあるアイデアを無効にすることができます。ここでweak_ptr
を使用して解決しようとしている問題は何ですか?
まだ誰も問題のパフォーマンスの側面について言及していないので、$ 0.02を投入させてください。
weak_ptr
は、対応するshared_ptr
sがすべてスコープ外になり、ポイントされたオブジェクトの割り当てが解除され、破棄されたときを何らかの方法で知る必要があります。これは、shared_ptr
sがそれぞれのweak_ptr
に対する破壊を何らかの方法で同じオブジェクトに伝える必要があることを意味します。これには一定のコストがかかります。たとえば、weak_ptr
がアドレスを取得する(またはオブジェクトが破棄される場合はnullptr
)グローバルハッシュテーブルを更新する必要があります。
これには、マルチスレッド環境でのロックも含まれるため、一部のタスクでは遅すぎる可能性があります。
ただし、unique_ptr
の目標は、ゼロコスト RAIIスタイルの抽象化クラスを提供することです。したがって、動的に割り当てられたオブジェクトのdelete
ing(またはdelete[]
ing)以外のコストは発生しません。たとえば、ロックされたハッシュテーブルアクセスまたはガードされたハッシュテーブルアクセスを行うことによって課される遅延は、割り当て解除のコストに匹敵する場合があり、unique_ptr
の場合は望ましくありません。
誰もがstd :: weak_ptrについてここに書いているように見えますが、著者が求めているのは弱いポイナーの概念ではないようです
標準ライブラリがunique_ptrにweak_ptrを提供していない理由について誰も言及していないと思います。弱いポインターCONCEPTはunique_ptrの使用を放棄しません。弱いポインターは、オブジェクトが既に削除されている場合にのみ情報であるため、魔法ではなく、非常に単純な一般化されたオブザーバーパターンです。
これは、スレッドセーフとshared_ptrとの一貫性のためです。
あなたは単に、他のスレッドに存在するunique_ptrから作成されたweak_ptrが、ポイントされたオブジェクトのメソッドの呼び出し中に破壊されないことを保証することはできません。これは、weak_ptrが、スレッドセーフを保証するstd :: shared_ptrと一貫している必要があるためです。 unique_ptrで正常に動作するweak_ptrを実装できますが、同じスレッドでのみ使用できます。この場合、ロックメソッドは不要です。 base :: WeakPtrおよびbase :: WeakPtrFactoryのクロムソースを確認できます。unique_ptrで自由に使用できます。 Chromiumの弱いポインタコードはおそらく最後のメンバーの破壊に基づいています-あなたは最後のメンバーとしてファクトリを追加する必要があり、その後WeakPtrはオブジェクトの削除に通知されていると信じています(私は100%確信していません)-それは見えません実装が難しい。
全体的に、弱いポインターの概念でunique_ptrを使用することは問題ありません。
unique_ptr
よりもshared_ptr
を好む理由を区別することが役立つ場合があります。
パフォーマンス明らかな理由の1つは、計算時間とメモリの使用です。現在定義されているように、shared_ptr
オブジェクトには通常、参照カウント値のようなものが必要です。 unique_ptr
オブジェクトはサポートしていません。
セマンティックスunique_ptr
を使用すると、プログラマは、指示されたオブジェクトが破棄されるとき、unique_ptr
が破棄されるとき、またはその変更メソッドが呼び出されます。そのため、大規模または馴染みのないコードベースでは、unique_ptr
を使用すると、プログラムの実行時動作に関する明らかでない情報を静的に伝達(および強制)します。
上記のコメントは一般に、weak_ptr
オブジェクトがunique_ptr
オブジェクトに結び付けられることは望ましくないというパフォーマンスベースの理由に焦点を当てています。しかし、セマンティクスベースの引数が、STLの将来のバージョンが元の質問で暗示されているユースケースをサポートするのに十分な理由であるかどうか疑問に思うかもしれません。