方法: weak_ptr インスタンスを作成して使用する
オブジェクトには、参照カウントをインクリメントせずに shared_ptr の基になるオブジェクトにアクセスする方法を格納する必要が生じることがあります。 通常、この状況は shared_ptr
インスタンス間に循環参照がある場合に発生します。
最適なデザインとして、可能な場合は必ずポインターの共有所有権を避けてください。 ただし、shared_ptr
インスタンスの共有所有権が必要な場合、それらのインスタンス間の循環参照が発生しないようにします。 循環参照を回避できない場合や、何らかの場合で循環参照が必要とされる場合でも、weak_ptr を使用して 1 人以上の所有者に別の shared_ptr
への弱い参照を与えてください。 weak_ptr
を使用すると、関連するインスタンスの既存のセットに結合される shared_ptr
を作成できますが、基になるメモリ リソースがまだ有効な場合のみです。 weak_ptr
自体は、参照カウントに参加しないため、参照カウントが 0 になるのを防止することはできません。 ただし、weak_ptr
を使用して、初期化に使用された shared_ptr
の新しいコピーの取得を試みることはできます。 メモリが既に削除されている場合、weak_ptr
の bool 演算子は false
を返します。 メモリがまだ有効である場合は、新しい共有ポインターが参照カウントをインクリメントし、shared_ptr
の変数がスコープ内に入っている限りメモリが有効であることを保証します。
例
次のコード例は、weak_ptr
を使用して循環依存関係を持つオブジェクトの削除を確証するケースを示しています。 例を調べる際は、代替ソリューションについて検討した後のみ作成されたと見なしてください。 Controller
オブジェクトは、コンピューター プロセスのいくつかの側面を表しており、独立して動作します。 各コントローラーは、他のコントローラーのステータスのクエリをいつでも実行できる必要があるため、この目的でそれぞれのコントローラーにプライベート vector<weak_ptr<Controller>>
が含まれています。 各ベクターには循環参照が含まれているため、weak_ptr
の代わりに shared_ptr
インスタンスが使用されます。
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
class Controller
{
public:
int Num;
wstring Status;
vector<weak_ptr<Controller>> others;
explicit Controller(int i) : Num(i), Status(L"On")
{
wcout << L"Creating Controller" << Num << endl;
}
~Controller()
{
wcout << L"Destroying Controller" << Num << endl;
}
// Demonstrates how to test whether the
// pointed-to memory still exists or not.
void CheckStatuses() const
{
for_each(others.begin(), others.end(), [](weak_ptr<Controller> wp) {
auto p = wp.lock();
if (p)
{
wcout << L"Status of " << p->Num << " = " << p->Status << endl;
}
else
{
wcout << L"Null object" << endl;
}
});
}
};
void RunTest()
{
vector<shared_ptr<Controller>> v{
make_shared<Controller>(0),
make_shared<Controller>(1),
make_shared<Controller>(2),
make_shared<Controller>(3),
make_shared<Controller>(4),
};
// Each controller depends on all others not being deleted.
// Give each controller a pointer to all the others.
for (int i = 0; i < v.size(); ++i)
{
for_each(v.begin(), v.end(), [&v, i](shared_ptr<Controller> p) {
if (p->Num != i)
{
v[i]->others.push_back(weak_ptr<Controller>(p));
wcout << L"push_back to v[" << i << "]: " << p->Num << endl;
}
});
}
for_each(v.begin(), v.end(), [](shared_ptr<Controller> &p) {
wcout << L"use_count = " << p.use_count() << endl;
p->CheckStatuses();
});
}
int main()
{
RunTest();
wcout << L"Press any key" << endl;
char ch;
cin.getline(&ch, 1);
}
Creating Controller0
Creating Controller1
Creating Controller2
Creating Controller3
Creating Controller4
push_back to v[0]: 1
push_back to v[0]: 2
push_back to v[0]: 3
push_back to v[0]: 4
push_back to v[1]: 0
push_back to v[1]: 2
push_back to v[1]: 3
push_back to v[1]: 4
push_back to v[2]: 0
push_back to v[2]: 1
push_back to v[2]: 3
push_back to v[2]: 4
push_back to v[3]: 0
push_back to v[3]: 1
push_back to v[3]: 2
push_back to v[3]: 4
push_back to v[4]: 0
push_back to v[4]: 1
push_back to v[4]: 2
push_back to v[4]: 3
use_count = 1
Status of 1 = On
Status of 2 = On
Status of 3 = On
Status of 4 = On
use_count = 1
Status of 0 = On
Status of 2 = On
Status of 3 = On
Status of 4 = On
use_count = 1
Status of 0 = On
Status of 1 = On
Status of 3 = On
Status of 4 = On
use_count = 1
Status of 0 = On
Status of 1 = On
Status of 2 = On
Status of 4 = On
use_count = 1
Status of 0 = On
Status of 1 = On
Status of 2 = On
Status of 3 = On
Destroying Controller0
Destroying Controller1
Destroying Controller2
Destroying Controller3
Destroying Controller4
Press any key
テストとして、ベクター others
を vector<shared_ptr<Controller>>
に変更した後、出力で、RunTest
が返されたときにデストラクターが呼び出されないことを確認してください。
関連項目
フィードバック
https://aka.ms/ContentUserFeedback」を参照してください。
以下は間もなく提供いたします。2024 年を通じて、コンテンツのフィードバック メカニズムとして GitHub の issue を段階的に廃止し、新しいフィードバック システムに置き換えます。 詳細については、「フィードバックの送信と表示