強力と脆弱の参照を c++/cli WinRTStrong and weak references in C++/WinRT

Windows ランタイムは、参照カウント システムです。重要性およびの違いについて理解するための重要なシステムでこのような強力と脆弱の参照 (および参照がどちらも、暗黙的ななどをこのポインター)。The Windows Runtime is a reference-counted system; and in such a system it's important for you to know about the significance of, and distinction between, strong and weak references (and references that are neither, such as the implicit this pointer). このトピックで後ほど、これらの参照を正しく管理する方法についての知識とスムーズに実行される信頼性の高いシステムと予期しない障害が発生した 1 つの違いを意味します。As you'll see in this topic, knowing how to manage these references correctly can mean the difference between a reliable system that runs smoothly, and one that crashes unpredictably. 言語プロジェクションの詳細をサポートするヘルパー関数を提供することでC +/cli WinRT簡単かつ正しくより複雑なシステムの構築の作業の半分が満たしていること。By providing helper functions that have deep support in the language projection, C++/WinRT meets you halfway in your work of building more complex systems simply and correctly.

安全にアクセスする、このクラス メンバーのコルーチンでのポインターSafely accessing the this pointer in a class-member coroutine

コード リストは、クラスのメンバー関数は、コルーチンの典型的な例を示します。The code listing below shows a typical example of a coroutine that's a member function of a class. できますコピーして貼り付けこの例を指定したファイルに、新しいWindows コンソール アプリケーション (C++/WinRT) プロジェクト。You can copy-paste this example into the specified files in a new Windows Console Application (C++/WinRT) project.

// pch.h
#pragma once
#include <iostream>
#include <winrt/Windows.Foundation.h>

// main.cpp : Defines the entry point for the console application.
#include "pch.h"

using namespace winrt;
using namespace Windows::Foundation;
using namespace std::chrono_literals;

struct MyClass : winrt::implements<MyClass, IInspectable>
{
    winrt::hstring m_value{ L"Hello, World!" };

    IAsyncOperation<winrt::hstring> RetrieveValueAsync()
    {
        co_await 5s;
        co_return m_value;
    }
};

int main()
{
    winrt::init_apartment();

    auto myclass_instance{ winrt::make_self<MyClass>() };
    auto async{ myclass_instance->RetrieveValueAsync() };

    winrt::hstring result{ async.get() };
    std::wcout << result.c_str() << std::endl;
}

MyClass::RetrieveValueAsyncによって時間を消費し、最終的のコピーを返します、MyClass::m_valueデータ メンバー。MyClass::RetrieveValueAsync spends some time working, and eventually it returns a copy of the MyClass::m_value data member. 呼び出すRetrieveValueAsync非同期オブジェクトを作成し、そのオブジェクトが暗黙的なこのポインター (最終的には、これをm_valueにアクセス)。Calling RetrieveValueAsync causes an asynchronous object to be created, and that object has an implicit this pointer (through which, eventually, m_value is accessed).

イベントの完全なシーケンスを次に示します。Here's the full sequence of events.

  1. メインのインスタンスMyClassが作成されます (myclass_instance)。In main, an instance of MyClass is created (myclass_instance).
  2. asyncオブジェクトを作成すると、ポイント (を使用してそのこの) にmyclass_instanceします。The async object is created, pointing (via its this) to myclass_instance.
  3. Winrt::Windows::Foundation::IAsyncAction::get関数は、数秒間をブロックしの結果を返しますRetrieveValueAsyncします。The winrt::Windows::Foundation::IAsyncAction::get function blocks for a few seconds, and then returns the result of RetrieveValueAsync.
  4. RetrieveValueAsyncの値を返しますthis->m_valueします。RetrieveValueAsync returns the value of this->m_value.

手順 4 では安全な限りこのは有効です。Step 4 is safe as long as this is valid.

しかし、非同期操作が完了する前に、クラスのインスタンスが破棄される場合でしょうか。But, what if the class instance is destroyed before the async operation completes? これは、すべての種類の方法は、非同期メソッドが完了する前に、クラスのインスタンスはスコープ外に出る可能性があります。There are all kinds of ways the class instance could go out of scope before the asynchronous method has completed. クラスのインスタンスに設定してそれをシミュレートできますが、nullptrします。But, we can simulate it by setting the class instance to nullptr.

int main()
{
    winrt::init_apartment();

    auto myclass_instance{ winrt::make_self<MyClass>() };
    auto async{ myclass_instance->RetrieveValueAsync() };
    myclass_instance = nullptr; // Simulate the class instance going out of scope.

    winrt::hstring result{ async.get() }; // Behavior is now undefined; crashing is likely.
    std::wcout << result.c_str() << std::endl;
}

クラスのインスタンスを破棄しました後、もう一度を参照しない直接しましたように見えます。After the point where we destroy the class instance, it looks like we don't directly refer to it again. 非同期のオブジェクトはもちろん、このを使用して、クラスのインスタンス内で格納されている値をコピーしようとしへのポインター。But of course the asynchronous object has a this pointer to it, and tries to use that to copy the value stored inside the class instance. コルーチンは、メンバー関数と使用できることが必要ですが、このimpunity のポインター。The coroutine is a member function, and it expects to be able to use its this pointer with impunity.

コードにこの変更により問題が発生、手順 4. で、クラスのインスタンスが破棄されたため、およびこのが無効になっています。With this change to the code, we run into a problem in step 4, because the class instance has been destroyed, and this is no longer valid. 非同期のオブジェクトが、クラスのインスタンス内の変数にアクセスしようとすると、すぐにはクラッシュ (または何か完全に定義されていません)。As soon as the asynchronous object attempts to access the variable inside the class instance, it will crash (or do something entirely undefined).

解決する非同期操作を付与するには—コルーチン—クラスのインスタンスへの独自の強力な参照です。The solution is to give the asynchronous operation—the coroutine—its own strong reference to the class instance. 現在の記述で、コルーチンを効率的に raw 保持このクラスのインスタンスへのポインターが、クラスのインスタンスを維持するのに十分な。As currently written, the coroutine effectively holds a raw this pointer to the class instance; but that's not enough to keep the class instance alive.

実装を変更すると、クラスのインスタンスを維持するRetrieveValueAsync以下に示す。To keep the class instance alive, change the implementation of RetrieveValueAsync to that shown below.

IAsyncOperation<winrt::hstring> RetrieveValueAsync()
{
    auto strong_this{ get_strong() }; // Keep *this* alive.
    co_await 5s;
    co_return m_value;
}

A C++WinRT クラス直接的または間接的に派生から/、 winrt::implements テンプレート。A C++/WinRT class directly or indirectly derives from the winrt::implements template. そのため、 C++/WinRT オブジェクトを呼び出すことができます、 implements.get_strong プロテクト メンバー関数への強い参照を取得するそのこれポインター。Because of that, the C++/WinRT object can call its implements.get_strong protected member function to retrieve a strong reference to its this pointer. 実際に使用する必要がないことに注意してください、strong_this変数を上記のコード例では呼び出すだけget_strongインクリメント、 C++/WinRT オブジェクトの参照カウントされ、暗黙的なこのポインターが無効です。Note that there's no need to actually use the strong_this variable in the code example above; simply calling get_strong increments the C++/WinRT object's reference count, and keeps its implicit this pointer valid.

重要

Get_strongのメンバー関数は、 winrt::implements構造体のテンプレートを呼び出せることからの直接または間接的に派生したクラスからのみwinrt::implementsなどをC++/WinRT クラス。Because get_strong is a member function of the winrt::implements struct template, you can call it only from a class that directly or indirectly derives from winrt::implements, such as a C++/WinRT class. 派生することに関する詳細情報のwinrt::implements、例についてを参照してくださいと作成者 Api をC++/WinRTFor more info about deriving from winrt::implements, and examples, see Author APIs with C++/WinRT.

これは、手順 4 に移動するときに以前の問題を解決します。This resolves the problem that we previously had when we got to step 4. クラスのインスタンスへの他のすべての参照が表示されない場合でも、コルーチンがその依存関係が安定したことを保証する予防措置を取得します。Even if all other references to the class instance disappear, the coroutine has taken the precaution of guaranteeing that its dependencies are stable.

強い参照が、適切でないかどうかは、代わりに呼び出すことができます implements::get_weak への弱い参照を取得するこのします。If a strong reference isn't appropriate, then you can instead call implements::get_weak to retrieve a weak reference to this. アクセスする前に強い参照を取得するにはことを確認してこのします。Just confirm that you can retrieve a strong reference before accessing this. ここでも、 get_weakのメンバー関数は、 winrt::implementsテンプレートの構造体。Again, get_weak is a member function of the winrt::implements struct template.

IAsyncOperation<winrt::hstring> RetrieveValueAsync()
{
    auto weak_this{ get_weak() }; // Maybe keep *this* alive.

    co_await 5s;

    if (auto strong_this{ weak_this.get() })
    {
        co_return m_value;
    }
    else
    {
        co_return L"";
    }
}

上記の例で、弱い参照は、強い参照が残っていないときに破棄されないクラス インスタンスを保持しません。In the example above, the weak reference doesn't keep the class instance from being destroyed when no strong references remain. ただしをメンバー変数にアクセスする前に強い参照を取得できるかどうかを確認する方法を示します。But it gives you a way of checking whether a strong reference can be acquired before accessing the member variable.

安全にアクセスする、このイベント処理デリゲートを使用してポインターSafely accessing the this pointer with an event-handling delegate

シナリオThe scenario

イベント処理に関する一般的な情報は、次を参照してください。 C + でデリゲートを使用してイベントを処理/cli WinRTします。For general info about event-handling, see Handle events by using delegates in C++/WinRT.

前のセクションには、コルーチンと同時実行性の面での潜在的な有効期間に関する問題が強調表示されます。The previous section highlighted potential lifetime issues in the areas of coroutines and concurrency. オブジェクトのメンバー関数、または内からイベントを処理する場合してオブジェクトのメンバー関数は、内側のラムダ関数がイベント受信者 (イベントを処理するオブジェクト) とイベント ソース (オブジェクトの相対的な有効期間について考慮する必要がありますが、イベントの発生)。But, if you handle an event with an object's member function, or from within a lambda function inside an object's member function, then you need to think about the relative lifetimes of the event recipient (the object handling the event) and the event source (the object raising the event). コード例をいくつか見てみましょう。Let's look at some code examples.

コード優先リスト定義、単純なEventSourceクラスに追加された任意のデリゲートによって処理される一般的なイベントを発生させます。The code listing below first defines a simple EventSource class, which raises a generic event that's handled by any delegates that have been added to it. このイベントの例の動作を使用する、 Windows::Foundation::EventHandler デリゲートの型が問題と解決策をここでは、すべてのデリゲート型に適用されます。This example event happens to use the Windows::Foundation::EventHandler delegate type, but the issues and remedies here apply to any and all delegate types.

次に、 EventRecipientクラスのハンドラーを提供する、 EventSource::Eventラムダ関数の形式でイベント。Then, the EventRecipient class provides a handler for the EventSource::Event event in the form of a lambda function.

// pch.h
#pragma once
#include <iostream>
#include <winrt/Windows.Foundation.h>

// main.cpp : Defines the entry point for the console application.
#include "pch.h"

using namespace winrt;
using namespace Windows::Foundation;

struct EventSource
{
    winrt::event<EventHandler<int>> m_event;

    void Event(EventHandler<int> const& handler)
    {
        m_event.add(handler);
    }

    void RaiseEvent()
    {
        m_event(nullptr, 0);
    }
};

struct EventRecipient : winrt::implements<EventRecipient, IInspectable>
{
    winrt::hstring m_value{ L"Hello, World!" };

    void Register(EventSource& event_source)
    {
        event_source.Event([&](auto&& ...)
        {
            std::wcout << m_value.c_str() << std::endl;
        });
    }
};

int main()
{
    winrt::init_apartment();

    EventSource event_source;
    auto event_recipient{ winrt::make_self<EventRecipient>() };
    event_recipient->Register(event_source);
    event_source.RaiseEvent();
}

イベント受信者が上の依存関係を持つラムダ イベント ハンドラーを持っているパターンは、そのこのポインター。The pattern is that the event recipient has a lambda event handler with dependencies on its this pointer. イベント受信者には、イベントのソースよりも長く保持、たびに、これらの依存関係はよりも長くなります。Whenever the event recipient outlives the event source, it outlives those dependencies. その場合は、共通ですが、パターンにも動作します。And in those cases, which are common, the pattern works well. UI ページでそのページ上にあるコントロールで発生したイベントを処理するときなど、明らかな場合があります。Some of these cases are obvious, such as when a UI page handles an event raised by a control that's on the page. ページには、ボタンがよりも長く保持—ハンドラーもよりも長く保持、ボタンをクリックします。The page outlives the button—so, the handler also outlives the button. これは、受信側がソースを所有する場合 (データ メンバーとしてなど)、または受信側とソースが兄弟関係にあり、他のオブジェクトによって直接所有されている場合に当てはまります。This holds true any time the recipient owns the source (as a data member, for example), or any time the recipient and the source are siblings and directly owned by some other object. ハンドラーが依存するこのオブジェクトに表示されない場合、有効期間の強弱を気にしなくても、通常どおりこのオブジェクトをキャプチャできます。If you're sure you have a case where the handler won't outlive the this that it depends on, then you can capture this normally, without consideration for strong or weak lifetime.

場合はまだあります、これハンドラー (非同期アクションおよび操作によって生成される入力候補および進行状況のイベントのハンドラーを含む) での使用がよりも長く保持とその対処方法を理解することが重要とします。But there are still cases where this doesn't outlive its use in a handler (including handlers for completion and progress events raised by asynchronous actions and operations), and it's important to know how to deal with them.

  • 非同期メソッドを実装するためにコルーチンを作成する場合は可能です。If you're authoring a coroutine to implement an asynchronous method, then it's possible.
  • 特定の XAML UI フレームワーク オブジェクト (SwapChainPanel など) を使用するまれなケースで、イベント ソースから登録解除しなくても、受信側が最終処理される場合は可能です。In rare cases with certain XAML UI framework objects (SwapChainPanel, for example), then it's possible, if the recipient is finalized without unregistering from the event source.

問題The issue

次のバージョンのメイン関数は、イベントの受信者が破棄されるときの動作をシミュレート (おそらくこれがスコープ外) イベント ソースがイベントを発生させても中にします。This next version of the main function simulates what happens when the event recipient is destroyed (perhaps it goes out of scope) while the event source is still raising events.

int main()
{
    winrt::init_apartment();

    EventSource event_source;
    auto event_recipient{ winrt::make_self<EventRecipient>() };
    event_recipient->Register(event_source);
    event_recipient = nullptr; // Simulate the event recipient going out of scope.
    event_source.RaiseEvent(); // Behavior is now undefined within the lambda event handler; crashing is likely.
}

イベント受信者が破棄されるが、内のラムダのイベント ハンドラーがまだサブスクライブしている、イベントイベント。The event recipient is destroyed, but the lambda event handler within it is still subscribed to the Event event. ラムダが逆参照しようとしたそのイベントが発生したときに、このポインターで、その時点では無効です。When that event is raised, the lambda attempts to dereference the this pointer, which is at that point invalid. コード ハンドラー (または、コルーチンの継続で) からのアクセス違反の結果、それを使用しようとしています。So, an access violation results from code in the handler (or in a coroutine's continuation) attempting to use it.

重要

、このような状況が発生した場合の有効期間について考慮する必要があります、これオブジェクトかどうかと、キャプチャされたこれオブジェクトには、キャプチャよりも長くなります。If you encounter a situation like this, then you'll need to think about the lifetime of the this object; and whether or not the captured this object outlives the capture. 場合は、キャプチャ、強力なまたは弱い参照の場合は、以下をご紹介します。If it doesn't, then capture it with a strong or a weak reference, as we'll demonstrate below.

または—である場合、シナリオ、スレッドの場合の考慮事項もできるようなります。—別のオプションは、イベント、または受信者のデストラクターでは、受信者が完了した後、ハンドラーを失効することです。Or—if it makes sense for your scenario, and if threading considerations make it even possible—then another option is to revoke the handler after the recipient is done with the event, or in the recipient's destructor. 参照してください登録されたデリゲートを取り消すします。See Revoke a registered delegate.

これは、ハンドラーを登録する方法です。This is how we're registering the handler.

event_source.Event([&](auto&& ...)
{
    std::wcout << m_value.c_str() << std::endl;
});

ラムダは、参照によって任意のローカル変数を自動的にキャプチャします。The lambda automatically captures any local variables by reference. そのため、この例で同等にも記述できます。So, for this example, we could equivalently have written this.

event_source.Event([this](auto&& ...)
{
    std::wcout << m_value.c_str() << std::endl;
});

どちらの場合にのみキャプチャするため、生このポインター。In both cases, we're just capturing the raw this pointer. 何も起こりません参照カウント、何も、現在のオブジェクトを妨げてから破棄されるようにします。And that has no effect on reference-counting, so nothing is preventing the current object from being destroyed.

ソリューションThe solution

このソリューションでは、強い参照をキャプチャします。The solution is to capture a strong reference. 強い参照され、参照カウントをインクリメント現在のオブジェクトを維持します。A strong reference does increment the reference count, and it does keep the current object alive. キャプチャ変数を宣言するだけです (と呼ばれるstrong_thisこの例では) への呼び出しで初期化と implements.get_strongへの強い参照を取得しています、 このポインター。You just declare a capture variable (called strong_this in this example), and initialize it with a call to implements.get_strong, which retrieves a strong reference to our this pointer.

重要

Get_strongのメンバー関数は、 winrt::implements構造体のテンプレートを呼び出せることからの直接または間接的に派生したクラスからのみwinrt::implementsなどをC++/WinRT クラス。Because get_strong is a member function of the winrt::implements struct template, you can call it only from a class that directly or indirectly derives from winrt::implements, such as a C++/WinRT class. 派生することに関する詳細情報のwinrt::implements、例についてを参照してくださいと作成者 Api をC++/WinRTFor more info about deriving from winrt::implements, and examples, see Author APIs with C++/WinRT.

event_source.Event([this, strong_this { get_strong()}](auto&& ...)
{
    std::wcout << m_value.c_str() << std::endl;
});

でも、現在のオブジェクトの自動的なキャプチャを省略しの代わりに、暗黙の型を使用してキャプチャ変数を通じてデータ メンバーにアクセスできますこのします。You can even omit the automatic capture of the current object, and access the data member through the capture variable instead of via the implicit this.

event_source.Event([strong_this { get_strong()}](auto&& ...)
{
    std::wcout << strong_this->m_value.c_str() << std::endl;
});

強い参照が、適切でないかどうかは、代わりに呼び出すことができます implements::get_weak への弱い参照を取得するこのします。If a strong reference isn't appropriate, then you can instead call implements::get_weak to retrieve a weak reference to this. だけを引き続き取得できる強い参照からメンバーにアクセスする前に確認します。Just confirm that you can still retrieve a strong reference from it before accessing members.

event_source.Event([weak_this{ get_weak() }](auto&& ...)
{
    if (auto strong_this{ weak_this.get() })
    {
        std::wcout << strong_this->m_value.c_str() << std::endl;
    }
});

メンバー関数をデリゲートとして使用する場合If you use a member function as a delegate

だけでなくラムダ関数の場合は、これらの原則にも適用されます、代理人としてメンバー関数を使用します。As well as lambda functions, these principles also apply to using a member function as your delegate. 構文は異なります、いくつかのコードを見てみましょう。The syntax is different, so let's look at some code. 最初に、raw を使用して、安全でないメンバー関数イベントのハンドラーをここではこのポインター。First, here's the potentially unsafe member function event handler, using a raw this pointer.

struct EventRecipient : winrt::implements<EventRecipient, IInspectable>
{
    winrt::hstring m_value{ L"Hello, World!" };

    void Register(EventSource& event_source)
    {
        event_source.Event({ this, &EventRecipient::OnEvent });
    }

    void OnEvent(IInspectable const& /* sender */, int /* args */)
    {
        std::wcout << m_value.c_str() << std::endl;
    }
};

これは、オブジェクトとそのメンバー関数を参照する標準的な従来の方法です。This is the standard, conventional way to refer to an object and its member function. セーフにするには、するには—時点では、Windows SDK のバージョン (Windows 10、バージョンは 1809) 10.0.17763.0—強力なまたはハンドラーが登録されている時点で弱い参照を確立します。To make this safe, you can—as of version 10.0.17763.0 (Windows 10, version 1809) of the Windows SDK—establish a strong or a weak reference at the point where the handler is registered. その時点では、イベントの受信者オブジェクトはまだ有効な状態に呼ばれます。At that point, the event recipient object is known to be still alive.

強力な参照を呼び出すだけ get_strong 、生の代わりにこのポインター。For a strong reference, just call get_strong in place of the raw this pointer. C +/cli WinRT により得られたデリゲートが、現在のオブジェクトへの強い参照を保持しているようになります。C++/WinRT ensures that the resulting delegate holds a strong reference to the current object.

event_source.Event({ get_strong(), &EventRecipient::OnEvent });

弱い参照の場合は、呼び出す get_weakします。For a weak reference, call get_weak. C +/cli WinRT により得られたデリゲートが弱い参照を保持しているようになります。C++/WinRT ensures that the resulting delegate holds a weak reference. 過去 1 分間にあると、バック グラウンドでデリゲートに厳密な弱い参照を解決しようとして成功した場合のみ、メンバー関数を呼び出します。At the last minute, and behind the scenes, the delegate attempts to resolve the weak reference to a strong one, and only calls the member function if it's successful.

event_source.Event({ get_weak(), &EventRecipient::OnEvent });

弱い参照の使用例を使用して、 SwapChainPanel::CompositionScaleChangedA weak reference example using SwapChainPanel::CompositionScaleChanged

このコード例では使用して、 SwapChainPanel::CompositionScaleChanged 弱い参照の他の図を使用してイベント。In this code example, we use the SwapChainPanel::CompositionScaleChanged event by way of another illustration of weak references. コードでは、受信者への弱い参照をキャプチャするラムダを使用して、イベント ハンドラーを登録します。The code registers an event handler using a lambda that captures a weak reference to the recipient.

winrt::Windows::UI::Xaml::Controls::SwapChainPanel m_swapChainPanel;
winrt::event_token m_compositionScaleChangedEventToken;

void RegisterEventHandler()
{
    m_compositionScaleChangedEventToken = m_swapChainPanel.CompositionScaleChanged([weak_this{ get_weak() }]
        (Windows::UI::Xaml::Controls::SwapChainPanel const& sender,
        Windows::Foundation::IInspectable const& object)
    {
        if (auto strong_this{ weak_this.get() })
        {
            strong_this->OnCompositionScaleChanged(sender, object);
        }
    });
}

void OnCompositionScaleChanged(Windows::UI::Xaml::Controls::SwapChainPanel const& sender,
    Windows::Foundation::IInspectable const& object)
{
    // Here, we know that the "this" object is valid.
}

ラムダのキャプチャ句で、一時変数を作成し、このオブジェクトの弱参照を表示します。In the lamba capture clause, a temporary variable is created, representing a weak reference to this. ラムダ式の本文で、このオブジェクトの強参照を取得する場合は、OnCompositionScaleChanged 関数が呼び出されます。In the body of the lambda, if a strong reference to this can be obtained, then the OnCompositionScaleChanged function is called. これにより、OnCompositionScaleChanged 内でこのオブジェクトを安全に使用することができます。That way, inside OnCompositionScaleChanged, this can safely be used.

C++/WinRT の弱参照Weak references in C++/WinRT

上記は、弱い参照が使用されている説明しました。Above, we saw weak references being used. 一般に、循環参照の重大な場合に適しています。In general, they're good for breaking cyclic references. XAML ベースの UI フレームワークのネイティブ実装の例では、—フレームワークの歴史的な設計により—弱い参照メカニズム C +/cli WinRT 循環参照を処理する必要があります。For example, for the native implementation of the XAML-based UI framework—because of the historic design of the framework—the weak reference mechanism in C++/WinRT is necessary to handle cyclic references. XAML では、外部で、可能性があります必要はありません弱い参照を使用する (not が何も本質的に XAML 固有それらについて)。Outside of XAML, though, you likely won't need to use weak references (not that there's anything inherently XAML-specific about them). はなく、たいてい、はず設計独自 C +/cli WinRT Api の循環参照と弱い参照する必要が生じないようにします。Rather you should, more often than not, be able to design your own C++/WinRT APIs in such a way as to avoid the need for cyclic references and weak references.

宣言するすべての型について、いつどこで弱参照が必要になるかが C++/WinRT に対してすぐに明白になるわけではありません。For any given type that you declare, it's not immediately obvious to C++/WinRT whether or when weak references are needed. したがって、C++/WinRT は構造体テンプレート winrt::implements で弱参照サポートを自動的に提供し、そこから直接的または間接的に独自の C++/WinRT の型を派生します。So, C++/WinRT provides weak reference support automatically on the struct template winrt::implements, from which your own C++/WinRT types directly or indirectly derive. 利用に応じた料金制度であるため、オブジェクトが IWeakReferenceSource で実際に照会されない限り料金はかかりません。It's pay-for-play, in that it doesn't cost you anything unless your object is actually queried for IWeakReferenceSource. また、そのサポートを除外することを明示的に選択することができます。And you can choose explicitly to opt out of that support.

コード例Code examples

winrt::weak_ref 構造体テンプレートは、クラス インスタンスへの弱参照を取得するための 1 つのオプションです。The winrt::weak_ref struct template is one option for getting a weak reference to a class instance.

Class c;
winrt::weak_ref<Class> weak{ c };

または、winrt::make_weak ヘルパー関数を使用できます。Or, you can use the use the winrt::make_weak helper function.

Class c;
auto weak = winrt::make_weak(c);

弱参照を作成してもオブジェクト自体の参照カウントには影響しません。制御ブロックが割り当てられるだけです。Creating a weak reference doesn't affect the reference count on the object itself; it just causes a control block to be allocated. その制御ブロックが弱参照セマンティクスの実装を処理します。That control block takes care of implementing the weak reference semantics. その後、弱参照から強参照への昇格を試みて、成功した場合は使用することができます。You can then try to promote the weak reference to a strong reference and, if successful, use it.

if (Class strong = weak.get())
{
    // use strong, for example strong.DoWork();
}

他の強参照が存在する場合、weak_ref::get の呼び出しにより参照カウントが増分され、呼び出し元に強参照が返されます。Provided that some other strong reference still exists, the weak_ref::get call increments the reference count and returns the strong reference to the caller.

弱参照サポートの除外Opting out of weak reference support

弱参照サポートは自動です。Weak reference support is automatic. ただし、winrt::no_weak_ref マーカー構造体をテンプレート引数として基底クラスに渡すことによって、そのサポートを明示的に除外することを選択できます。But you can choose explicitly to opt out of that support by passing the winrt::no_weak_ref marker struct as a template argument to your base class.

winrt::implements から直接派生する場合。If you derive directly from winrt::implements.

struct MyImplementation: implements<MyImplementation, IStringable, no_weak_ref>
{
    ...
}

ランタイム クラスを作成している場合。If you're authoring a runtime class.

struct MyRuntimeClass: MyRuntimeClassT<MyRuntimeClass, no_weak_ref>
{
    ...
}

可変個引数パラメーター パックのどこにマーカー構造体が現れるかは関係ありません。It doesn't matter where in the variadic parameter pack the marker struct appears. 除外された型に対して弱参照を要求すると、コンパイラーは "これは弱参照サポート専用です" というメッセージで知らせます。If you request a weak reference for an opted-out type, then the compiler will help you out with "This is only for weak ref support".

重要な APIImportant APIs