weak_ptr の役割を除いて、shared_ptr がどのように機能するかを理解しています。参照カウントがゼロでない場合に循環参照を検出することは理解していますが、これを超えると、これがどのように行われるのか正確にはわかりません。それは何をするためのものか?
2 に答える
参照: std::weak_ptr が役立つのはいつですか? なぜ、そしてweak_ptrはどのように機能するのですか? 方法については。
私がどのように使用されているかの例を提供しますが、私が作成したサンプル コードは少し複雑なので、ご容赦ください。
#include <vector>
#include <memory>
#include <ostream>
int main()
{
// Fill container with values 1-50. This container OWNS these values.
std::vector<std::shared_ptr<int>> owning_container;
for(int i = 1; i <= 50; ++i)
{
owning_container.emplace_back(std::make_shared<int>(i));
}
// Create a sepearate container that references all owned values that are multiples of 5.
std::vector<std::weak_ptr<int>> referencing_container;
for(std::shared_ptr<int> const& i : owning_container)
{
if((*i) % 5 == 0)
{
// Make weak_ptr that references shared_ptr
referencing_container.emplace_back(i);
}
}
// Go through the owned values and delete all that are multiples of 10.
for(auto it = owning_container.begin(); it != owning_container.end();)
{
std::shared_ptr<int> const& i = *it;
if(*i % 10 == 0)
{
it = owning_container.erase(it);
}
else
{
++it;
}
}
// Now go through the referencing container and print out all values.
// If we were dealing with raw pointers in both containers here we would access deleted memory,
// since some of the the actual resources (in owning_container) that referencing_container
// references have been removed.
for(std::weak_ptr<int> const& i_ref : referencing_container)
{
// Check if the shared resource still exists before using it (purpose of weak_ptr)
std::shared_ptr<int> i = i_ref.lock();
if(i)
{
std::cout << *i << std::endl;
}
}
return 0;
}
ここでは、いくつかの共有リソース (この場合は int) を含むコンテナー ( shared_ptr
) があり、別のコンテナーが参照する必要があります ( weak_ptr
)。参照元はリソースを所有していません。存在する場合にのみアクセスできる必要があります。参照されているリソースがまだ生きているかどうかを確認するためweak_ptr
に、shared_ptr
を usingに変換しweak_ptr::lock()
ます。まだ存在するリソースには、shared_ptr
によって返される有効な がありますlock()
。もう存在しないものは null を返しますshared_ptr
。shared_ptr
をoperator bool()
使用する前に null かどうかを確認するために使用できる があります。
ゲーム内のすべてのオブジェクトがgame_object
. シークするターゲットを必要とする、敵のためのある種のシーク ロジックがあるとgame_object
します。上記を使用すると、敵にweak_ptr<game_object>
. これは所有していませんgame_object
。他の何かがそのターゲットを殺した場合、そのターゲットは死ぬべきです。shared_ptr
敵が代わりにa を持っていた場合に発生するような辺鄙な状態でぶら下がることはありません。このようにして、敵のターゲットがまだ生きている場合 (をロックすることで確認できますweak_ptr
)、シーク ロジックを実行できます。それ以外の場合は、新しいターゲットを見つけることができます。の「所有者」はgame_object
ある種のgame_world
クラスである可能性があります-これには次のコンテナがありますshared_ptr<game_object>
. 敵が新しいターゲットを必要とする場合、このコンテナを検索して、weak_ptr
から作成することができgame_world
ますshared_ptr
。
弱いポインターは、リソースの所有権を主張しませんが、それを参照するだけです。したがって、(メソッドを使用して) 所有権をもう一度主張する以外に、リソースを操作することはできませんweak_ptr::lock()
。私見、そのような動作が望まれる最も頻繁な現実の状況は、循環依存関係と(それほど頻繁ではありませんが)キャッシングです。
ポインタの相互参照カウントが 1 未満になることは決してないため、共有ポインタのみで作成された循環的な依存関係は、事実上のメモリ リークです。弱いポインターは、この状況を「検出」しません。所有権のループを断ち切るだけで、トラブルが入り込むことはありません。弱いポインターをロックすることで「チェーンの両端を接続」することはできますが、弱いポインターを介して取得する可能性のある共有ポインターはどれも持続しません。
キャッシュの問題は、キャッシュが通常、キャッシュされたコンテンツの有効期間に影響を与えるべきではないということです。これはキャッシュの義務ではありません。しかし、キャッシュが共有ポインタを保持する場合、キャッシュと対話せずにキャッシュされたオブジェクトの存続期間を終了することはできず、これはしばしば不便です。