C++/WinRT'de güçlü ve zayıf referanslar

Önemli

Windows Uygulama SDK'sı ile uygulama geliştiriyor musunuz? Bu makalenin kodu UWP (Windows.UI.Xaml) ad alanlarını kullanır. Projeniz WinUI 3'i (Windows Uygulama SDK'sı) hedeflediyse, Microsoft.UI.Xaml yerine (ve ilgili Microsoft.UI.* ad alanlarını) ekleyin. Tam eşleme için UWP API'lerini Windows Uygulama SDK'sı'sına eşleme'ye, ek ayrıntılar için ise UI geçiş kılavuzu'na bakın.

Windows Çalışma Zamanı, referans sayımlı bir sistemdir; böyle bir sistemde güçlü ve zayıf referansların önemini ve aralarındaki farkı bilmeniz önemlidir (ayrıca örtük this işaretçisi gibi ikisi de olmayan referansları da). Bu konuda göreceğiniz gibi, bu referansların doğru şekilde nasıl yönetileceğini bilmek, sorunsuz çalışan güvenilir bir sistem ile öngörülemez biçimde çöken bir sistem arasındaki farkı yaratabilir. C++/WinRT, dil projeksiyonunda derin desteğe sahip yardımcı işlevler sağlayarak, daha karmaşık sistemler oluşturma çalışmanızın yarısında size basit ve doğru bir şekilde yanıtlar.

Note

Yalnızca birkaç özel durumla, C++/WinRT'de kullandığınız veya yazdığınız Windows Çalışma Zamanı türleri için zayıf başvuru desteği varsayılan olarak açıktır. Windows. UI. Kompozisyon ve Windows. Devices.Input.PenDevice, bu türlerde zayıf başvuru desteğinin açık olmadığı ad alanları gibi özel durum örnekleridir. Ayrıca bkz. Otomatik iptal temsilciniz kaydedilemiyorsa.

Türler tanımlıyorsanız, bu konudaki C++/WinRT'de zayıf başvurular bölümüne bakın.

Sınıf üyesi bir eş yordamda this işaretçisine güvenli biçimde erişim

Eş yordamlar ve kod örnekleri hakkında daha fazla bilgi için C++/WinRT ile eşzamanlılık ve zaman uyumsuz işlemler bölümüne bakın.

Aşağıdaki kod listesi, sınıfın üye işlevi olan tipik bir coroutine örneğini gösterir. Bu örneği yeni bir Windows Konsol Uygulaması (C++/WinRT) projesinde belirtilen dosyalara kopyalayıp yapıştırabilirsiniz.

// 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 biraz zaman harcar ve sonunda veri üyesinin MyClass::m_value bir kopyasını döndürür. RetrieveValueAsync çağrısı, zaman uyumsuz bir nesnenin oluşturulmasına neden olur ve bu nesnenin örtük bir this işaretçisi vardır (sonunda m_value üzerinden erişilir).

Bir eş yordamda yürütmenin, denetimin çağırana geri döndüğü ilk askıya alma noktasına kadar senkron ilerlediğini unutmayın. RetrieveValueAsync'te ilk co_await askıya alma noktasıdır. Coroutine yeniden çalışmaya başladığında (bu örnekte yaklaşık beş saniye sonra), m_value öğesine eriştiğimiz örtük this işaretçisi üzerinden her şey olmuş olabilir.

Olay dizisinin tamamı aşağıdadır.

  1. Main'da bir MyClass örneği oluşturulur (myclass_instance).
  2. async nesnesi oluşturulur ve this aracılığıyla myclass_instance öğesini işaret eder.
  3. winrt::Windows::Foundation::IAsyncAction::get işlevi ilk askıya alma noktasına isabet eder, birkaç saniye bloklar ve sonra RetrieveValueAsync sonucunu döndürür.
  4. RetrieveValueAsync değerini this->m_valuedöndürür.

4. adım yalnızca geçerli olduğu sürece güvenlidir.

Peki eşzamansız işlem tamamlanmadan önce sınıf örneği yok edilirse ne olur? Zaman uyumsuz yöntem tamamlanmadan önce sınıf örneğinin kapsam dışına çıkabileceği pek çok durum vardır. Ancak sınıf örneğini nullptrolarak ayarlayarak simülasyonunu yapabilirsiniz.

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;
}

Sınıf örneğini yok ettiğimiz noktadan sonra, görünüşe göre ona bir daha doğrudan başvurmuyoruz. Ancak elbette eşzamansız nesne, kendisine ait bir this işaretçisine sahiptir ve sınıf örneğinin içinde depolanan değeri kopyalamak için bu işaretçiyi kullanmaya çalışır. Coroutine bir üye işlevidir ve this işaretçisini rahatça kullanabilmesini bekler.

Kodda yapılan bu değişiklikle, sınıf örneği yok edildiğinden ve bu artık geçerli olmadığından 4. adımda bir sorunla karşılaşırız. Zaman uyumsuz nesne sınıf örneğinin içindeki değişkene erişmeye çalıştığında, kilitlenir (veya tamamen tanımlanmamış bir şey yapar).

Çözüm, asenkron işleme —eş yordam— sınıf örneğine kendi güçlü referansını vermektir. Şu anki yazımıyla, eşyordam fiilen sınıf örneğine ait ham bir this işaretçisi tutar; ancak bu, sınıf örneğinin yaşamını sürdürmesini sağlamak için yeterli değildir.

Sınıf örneğini canlı tutmak için RetrieveValueAsync uygulamasını aşağıda gösterilen şekilde değiştirin.

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

C++/WinRT sınıfı doğrudan veya dolaylı olarak winrt::implements şablonundan türetilir. Bu nedenle, C++/WinRT nesnesi, implements::get_strong korumalı üye işlevini çağırarak this işaretçisine güçlü bir başvuru elde edebilir. Yukarıdaki kod örneğinde değişkenin gerçekten kullanılmasına strong_this gerek olmadığını unutmayın; yalnızca get_strong çağrısı C++/WinRT nesnesinin başvuru sayısını artırır ve bu işaretçinin örtük değerini geçerli tutar.

Önemli

get_strongwinrt::implements yapı şablonunun üye işlevi olduğundan, bunu yalnızca doğrudan veya dolaylı olarak winrt::implements sınıfından türetilen bir sınıftan çağırabilirsiniz( örneğin, C++/WinRT sınıfı). winrt::implements ve örneklerinden türetme hakkında daha fazla bilgi için bkz. C++/WinRT ile API'ler yazma.

Bu, 4. adıma gittiğimizde daha önce sahip olduğumuz sorunu çözer. Sınıf örneğine yapılan diğer tüm referanslar ortadan kalksa bile, coroutine bağımlılıklarının kararlı kalacağını güvence altına alma önlemini almıştır.

Güçlü bir referans uygun değilse, bunun yerine implements::get_weak çağrısını kullanarak this için zayıf bir referans elde edebilirsiniz. this öğesine erişmeden önce güçlü bir referans alabileceğinizi doğrulayın. Yine, get_weak, winrt::implements yapı şablonunun bir üye işlevidir.

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"";
    }
}

Yukarıdaki örnekte zayıf başvuru, güçlü başvuru kalmadığında sınıf örneğinin yok edilmesine engel olmaz. Ancak üye değişkenine erişmeden önce güçlü bir referans edinilip edinilemeyeceğini kontrol etmenizi sağlar.

Olay işleme temsilcisiyle bu işaretçiye güvenli bir şekilde erişme

Senaryo

Olay işleme hakkında genel bilgi için bkz. C++/WinRT'de temsilcileri kullanarak olayları işleme.

Önceki bölümde, eş yordamlar ve eşzamanlılık alanlarındaki olası yaşam süresi sorunları vurgulanmıştır. Ancak, bir olayı nesnenin üye işleviyle veya nesnenin üye işlevinin içindeki lambda işlevinden işlerseniz, olay alıcısının (olayı işleyen nesne) ve olay kaynağının (olayı yükselten nesne) göreli yaşam sürelerini düşünmeniz gerekir. Şimdi bazı kod örneklerine göz atalım.

Aşağıdaki kod listesi ilk olarak basit bir EventSource sınıfı tanımlar ve bu sınıfa eklenmiş olan tüm temsilciler tarafından işlenen genel bir olay oluşturur. Bu örnek olay Windows::Foundation::EventHandler temsilci türünü kullanır, ancak buradaki sorunlar ve çözümler tüm temsilci türleri için geçerlidir.

Ardından EventRecipient sınıfı, bir lambda işlevi biçiminde EventSource::Event olayı için bir işleyici sağlar.

// 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();
}

Örüntü, olayın alıcısının this işaretçisine bağımlı bir lambda olay işleyicisine sahip olmasıdır. Olay alıcısı, olay kaynağından daha uzun ömürlü olduğunda, bu bağımlılıkların da ömrünü aşar. Ve yaygın olan bu durumlarda, desen iyi çalışır. Bu durumlardan bazıları, örneğin kullanıcı arabirimi sayfasının sayfadaki bir denetim tarafından tetiklenen bir olayı işlemesi gibi açıktır. Sayfanın ömrü düğmenin ömründen daha uzundur; dolayısıyla olay işleyicisinin ömrü de düğmenin ömründen daha uzundur. Bu, alıcının kaynak nesneye sahip olduğu durumlarda (örneğin bir veri üyesi olarak) veya alıcı ile kaynak kardeş nesneler olup doğrudan başka bir nesne tarafından sahiplenildiği durumlarda geçerlidir.

İşleyicinin, bağımlı olduğu this nesnesinden daha uzun yaşamayacağından eminseniz, güçlü veya zayıf yaşam süresini dikkate almadan this'i normal şekilde yakalayabilirsiniz.

Ancak yine de, this nesnesinin bir işleyicideki kullanım süresini aşmadığı durumlar vardır (buna, zaman uyumsuz eylem ve işlemler tarafından tetiklenen tamamlanma ve ilerleme olaylarının işleyicileri de dahildir) ve bunlarla nasıl başa çıkılacağını bilmek önemlidir.

  • Olay kaynağı olaylarını zaman uyumlu bir şekilde yükselttiğinde, işleyicinizi iptal edebilir ve daha fazla olay almayacağınızdan emin olabilirsiniz. Ancak zaman uyumsuz olaylar için, iptal işleminden sonra bile (ve özellikle yıkıcı içinde iptal ederken), yok etme işlemi başladıktan sonra bir uçuş içi olay nesnenize ulaşabilir. Yok edilmeden önce aboneliği kaldırabileceğiniz bir yer bulmak sorunu hafifletebilir, ancak sağlam bir çözüm için okumaya devam edebilir.
  • Zaman uyumsuz bir yöntem uygulamak için bir coroutine yazarsanız, bu mümkündür.
  • Nadir durumlarda, belirli XAML UI çerçevesi nesnelerinde (örneğin SwapChainPanel), alıcı nesne olay kaynağındaki kaydı kaldırılmadan sonlandırılırsa bu mümkün olabilir.

Sorun

Ana işlevin bu sonraki sürümü, olay kaynağı hala olayları oluştururken olay alıcısı yok edildiğinde (belki de kapsamın dışına çıktığında) ne olacağının benzetimini oluşturur.

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.
}

Olay alıcısı yok edilir, ancak içindeki lambda olay işleyicisi olay olayına abone olmaya devam eder. Bu olay tetiklendiğinde lambda, bu noktada geçersiz olan bu işaretçiye başvurmayı dener. Bu nedenle erişim ihlali, işleyicideki (veya bir eş yordamdaki) kodu kullanmaya çalışan koddan kaynaklanmaktadır.

Önemli

Böyle bir durumla karşılaşırsanız, this nesnesinin yaşam süresi hakkında düşünmeniz gerekir; ayrıca yakalanan this nesnesinin yakalamanın ötesinde varlığını sürdürüp sürdürmediğini de değerlendirmelisiniz. Eğer öyle olmazsa, aşağıda göstereceğimiz gibi onu güçlü ya da zayıf bir referansla yakalayın.

Ya da—senaryonuz için anlamlıysa ve iş parçacığıyla ilgili hususlar bunu mümkün kılıyorsa—başka bir seçenek de, alıcı olayla işini bitirdikten sonra veya alıcının yıkıcısında işleyiciyi kaldırmaktır. Bkz. Kayıtlı temsilciyi iptal etme.

İşleyiciyi bu şekilde kaydediyoruz.

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

Lambda ifadesi, tüm yerel değişkenleri referansla otomatik olarak yakalar. Bu nedenle, bu örnekte, bunu eşdeğer bir şekilde yazmış da olabilirdik.

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

Her iki durumda da bu işaretçinin ham öğesini yakalamaya çalışıyoruz. Ve bunun referans sayımı üzerinde hiçbir etkisi yoktur, dolayısıyla mevcut nesnenin yok edilmesini engelleyen bir şey yoktur.

Çözüm

Çözüm, güçlü bir referans tutmaktır (ya da göreceğimiz gibi, bu daha uygunsa zayıf bir referans). Güçlü bir referans, başvuru sayısını artırır ve mevcut nesneyi canlı tutar. Yalnızca bir yakalama değişkeni bildirirsiniz (bu örnekte strong_this olarak adlandırılır) ve bunu, implements::get_strong çağrısıyla başlatırsınız; bu çağrı, this işaretçimize güçlü bir başvuru elde eder.

Önemli

get_strongwinrt::implements yapı şablonunun üye işlevi olduğundan, bunu yalnızca doğrudan veya dolaylı olarak winrt::implements sınıfından türetilen bir sınıftan çağırabilirsiniz( örneğin, C++/WinRT sınıfı). winrt::implements ve örneklerinden türetme hakkında daha fazla bilgi için bkz. C++/WinRT ile API'ler yazma.

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

Hatta mevcut nesnenin otomatik olarak yakalanmasını bile atlayabilir ve veri üyesine örtük this yerine yakalama değişkeni aracılığıyla erişebilirsiniz.

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

Güçlü bir referans uygun değilse, bunun yerine implements::get_weak çağrısını kullanarak this için zayıf bir referans elde edebilirsiniz. Zayıf başvuru, mevcut nesneyi canlı tutmaz. Bu nedenle, üyelere erişmeden önce zayıf başvurudan hala güçlü bir başvuru alabildiğinizi onaylayın.

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;
    }
});

Ham bir işaretçi yakalarsanız, işaret edilen nesneyi canlı tuttuğunuzdan emin olmanız gerekir.

Bir üye fonksiyonu delege olarak kullanıyorsanız

Lambda işlevlerinin yanı sıra, bu ilkeler temsilci olarak üye işlevini kullanmak için de geçerlidir. Söz dizimi farklıdır, bu nedenle bazı kodlara göz atalım. İlk olarak, ham bir this işaretçisi kullanan, potansiyel olarak güvenli olmayan üye işlevi olay işleyicisi aşağıdadır.

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;
    }
};

Bu, bir nesneye ve üye işlevine başvurmanın standart, geleneksel yoludur. Bunu güvenli hale getirmek için, Windows SDK'sının 10.0.17763.0 (Windows 10, sürüm 1809) itibarıyla işleyicinin kaydedildiği noktada güçlü veya zayıf bir başvuru oluşturabilirsiniz. Bu noktada, olay alıcı nesnesinin hâlâ var olduğu bilinmektedir.

Güçlü bir referans için, ham this işaretçisi yerine yalnızca get_strong çağırın. C++/WinRT, ortaya çıkan delegate’in geçerli nesneye güçlü bir başvuru tutmasını sağlar.

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

Güçlü bir referans yakalamak, nesnenizin ancak işleyicinin kaydı kaldırıldıktan ve bekleyen tüm geri çağırmalar tamamlandıktan sonra yok edilmeye uygun hâle geleceği anlamına gelir. Ancak bu garanti yalnızca olay tetiklendiği anda geçerlidir. Olay işleyiciniz eşzamansızsa, ilk askıya alma noktasından önce korutininize sınıf örneğine yönelik güçlü bir referans oluşturmanız gerekir (ayrıntılar ve kod için, bu konunun önceki kısmındaki Bir sınıf üyesi korutinde this işaretçisine güvenle erişme bölümüne bakın). Ancak bu, olay kaynağınızla nesneniz arasında döngüsel bir başvuru oluşturur, bu nedenle olayınızı iptal ederek bunu açıkça kesmeniz gerekir.

Zayıf bir referans için get_weak çağırın. C++/WinRT, ortaya çıkan temsilcinin zayıf başvuruya sahip olmasını sağlar. Son anda ve arka planda, delege zayıf referansı güçlü bir referansa dönüştürmeye çalışır ve yalnızca bu işlem başarılı olursa üye fonksiyonu çağırır.

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

Temsilci üye işlevinizi çağırırsa, işleyiciniz dönene kadar C++/WinRT nesnenizi canlı tutar. Ancak işleyiciniz asenkron ise, yürütme askıya alma noktalarında geri döner; bu nedenle, ilk askıya alma noktasından önce coroutine’inize sınıf örneğine güçlü bir referans vermeniz gerekir. Yine, daha fazla bilgi için bu konunun önceki bölümlerinde yer alan Sınıf üyesi bir eş yordamda this işaretçisine güvenli bir şekilde erişme başlıklı bölüme bakın.

Üye işlevi bir Windows Çalışma Zamanı türüne ait değilse

get_strong yöntemi kullanılabilir olmadığında (türünüz Windows Çalışma Zamanı bir tür değilse), aşağıdaki kod örneğinde gösterilen tekniği kullanabilirsiniz. Burada, NetworkInformation.NetworkStatusChanged olayını işleyen normal bir C++ sınıfı (ConsoleNetworkWatcher adlı) gösterilir.

#include <winrt/Windows.Networking.Connectivity.h>
using namespace winrt;
using namespace Windows::Networking::Connectivity;

class ConsoleNetworkWatcher
{
    /* any constructor, and instance methods, here*/

    static void Initialize(std::shared_ptr<ConsoleNetworkWatcher> instance)
    {
        auto weakPointer{ std::weak_ptr{ instance } };

        instance->m_statusChangedRevoker =
            NetworkInformation::NetworkStatusChanged(winrt::auto_revoke,
                [weakPointer](winrt::Windows::Foundation::IInspectable const& sender)
                {
                    auto sharedPointer{ weakPointer.lock() };

                    if (sharedPointer)
                    {
                        sharedPointer->NetworkStatusChanged(sender);
                    }
                });
    }

    void NetworkStatusChanged(winrt::Windows::Foundation::IInspectable const& sender){/* handle event here */};

private:
    NetworkInformation::NetworkStatusChanged_revoker m_statusChangedRevoker;
};

SwapChainPanel::CompositionScaleChanged kullanan zayıf başvuru örneği

Bu kod örneğinde, SwapChainPanel::CompositionScaleChanged olayını, zayıf başvuruların başka bir örneği olarak kullanıyoruz. Kod, alıcı nesneye zayıf bir referans yakalayan bir lambda kullanarak bir olay işleyicisi kaydeder.

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

void RegisterEventHandler()
{
    m_compositionScaleChangedEventToken = m_swapChainPanel.CompositionScaleChanged([weak_this{ get_weak() }]
        (Microsoft::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(Microsoft::UI::Xaml::Controls::SwapChainPanel const& sender,
    Windows::Foundation::IInspectable const& object)
{
    // Here, we know that the "this" object is valid.
}

Lambda yakalama ifadesinde, this öğesine yönelik zayıf bir başvuruyu temsil eden geçici bir değişken oluşturulur. Lambda gövdesinde, this için güçlü bir başvuru elde edilebilirse, OnCompositionScaleChanged işlevi çağrılır. Böylece, OnCompositionScaleChanged içinde this güvenle kullanılabilir.

C++/WinRT'de zayıf başvurular

Yukarıda zayıf referansların kullanıldığını gördük. Genel olarak, döngüsel referansları kırmak için uygundurlar. Örneğin, çerçevenin geçmiş tasarımı nedeniyle XAML tabanlı UI çerçevesinin yerel uygulaması için C++/WinRT'deki zayıf başvuru mekanizması döngüsel başvuruları işlemek için gereklidir. Yine de, XAML’ın dışında muhtemelen zayıf referanslar kullanmanıza gerek duymayacaksınız (ama bu, bunların doğası gereği XAML’e özgü olduğu anlamına gelmez). Bunun yerine, çoğu durumda, kendi C++/WinRT API'lerinizi döngüsel referanslara ve zayıf referanslara ihtiyaç duymayacak şekilde tasarlayabilmelisiniz.

Tanımladığınız herhangi bir tür için, C++/WinRT açısından zayıf başvuruların gerekip gerekmediği veya ne zaman gerektiği hemen açık değildir. Bu nedenle, C++/WinRT, kendi C++/WinRT türünüzün doğrudan veya dolaylı olarak türetildiği winrt::implements yapısı şablonunda otomatik olarak zayıf başvuru desteği sağlar. Bu, nesneniz IWeakReferenceSource için sorgulanmadığı sürece size hiçbir şeye mal olmaması için ücret ödeme yöntemidir. Ayrıca bu destekten vazgeçmeyi açıkça seçebilirsiniz.

Kod örnekleri

winrt::weak_ref yapı şablonu, bir sınıf örneğine zayıf başvuru elde etmek için seçeneklerden biridir.

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

İsterseniz winrt::make_weak yardımcı işlevini kullanabilirsiniz.

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

Zayıf referans oluşturmak, nesnenin kendi referans sayısını etkilemez; yalnızca bir kontrol bloğu ayrılmasına neden olur. Bu denetim bloğu, zayıf başvuru semantiğinin uygulanmasıyla ilgilenir. Daha sonra zayıf başvuruyu güçlü bir başvuruya yükseltmeyi deneyebilir ve başarılı olursa bunu kullanabilirsiniz.

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

Başka bir güçlü başvurunun hala mevcut olması koşuluyla , weak_ref::get çağrısı başvuru sayısını artırır ve arayan için güçlü başvuruyu döndürür.

Zayıf referans desteğini devre dışı bırakma seçeneği

Zayıf referans desteği otomatik olarak sağlanır. Ancak winrt::no_weak_ref işaretçi yapısını temel sınıfınıza şablon bağımsız değişkeni olarak geçirerek bu desteği geri çevirmeyi açıkça seçebilirsiniz.

winrt::implements sınıfından doğrudan türetiyorsanız.

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

Bir çalışma zamanı sınıfı oluşturuyorsanız.

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

İşaretçi yapısının variadic parametre paketinde nerede göründüğü önemli değildir. Hariç tutulmuş bir tür için zayıf başvuru isterseniz, derleyici "Bu yalnızca zayıf başvuru desteği içindir" ile size yardımcı olur.

Önemli API'ler