Referensi yang kuat dan lemah dalam C++/WinRT

Important

Membangun dengan SDK Aplikasi Windows? Kode artikel ini menggunakan namespace UWP (Windows.UI.Xaml). Jika proyek Anda menargetkan WinUI 3 (SDK Aplikasi Windows), ganti Microsoft.UI.Xaml (dan namespace terkait Microsoft.UI.*) di seluruh kode. Lihat Memetakan API UWP ke SDK Aplikasi Windows untuk panduan pemetaan lengkap dan migrasi UI untuk detail tambahan.

Windows Runtime adalah sistem dengan penghitungan referensi; dan dalam sistem seperti itu, penting bagi Anda untuk memahami pentingnya, serta perbedaan antara, referensi kuat dan referensi lemah (dan referensi yang bukan keduanya, seperti pointer this implisit). Seperti yang akan Anda lihat dalam topik ini, mengetahui cara mengelola referensi ini dengan benar dapat berarti perbedaan antara sistem yang dapat diandalkan yang berjalan dengan lancar, dan yang mengalami crash tanpa diduga. Dengan menyediakan fungsi pembantu yang didukung secara mendalam dalam proyeksi bahasa, C++/WinRT membantu Anda dalam membangun sistem yang lebih kompleks secara sederhana dan benar.

Note

Dengan hanya beberapa pengecualian, dukungan referensi lemah aktif secara default untuk tipe Windows Runtime yang Anda gunakan atau buat di C++/WinRT. Windows. UI. Komposisi dan Windows. Devices.Input.PenDevice adalah contoh pengecualian—yaitu, namespace di mana dukungan referensi yang lemah tidak aktif untuk jenis tersebut. Lihat juga Jika delegasi pencabutan otomatis Anda gagal didaftarkan.

Jika Anda membuat tipe, silakan lihat bagian Referensi lemah di C++/WinRT dalam topik ini.

Mengakses pointer ini dengan aman dalam koroutine anggota kelas

Untuk informasi selengkapnya tentang coroutines, dan contoh kode, lihat Operasi konkurensi dan asinkron dengan C++/WinRT.

Listing kode di bawah ini menunjukkan contoh tipikal korutin yang menjadi fungsi anggota suatu kelas. Anda dapat menyalin-tempel contoh ini ke dalam file yang ditentukan dalam proyek Aplikasi Konsol Windows baru (C++/WinRT).

// 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 menghabiskan waktu untuk bekerja, dan akhirnya mengembalikan salinan MyClass::m_value anggota data. Memanggil RetrieveValueAsync menyebabkan objek asinkron dibuat, dan objek tersebut memiliki penunjuk ini implisit (melaluinya, akhirnya, m_value diakses).

Ingatlah bahwa, dalam koroutine, eksekusi berlangsung secara sinkron hingga mencapai titik penangguhan pertama, dan pada titik itu kontrol dikembalikan kepada pemanggil. Di RetrieveValueAsync, yang pertama co_await adalah titik suspensi pertama. Pada saat coroutine dilanjutkan kembali (sekitar lima detik kemudian, dalam kasus ini), banyak hal bisa saja terjadi pada pointer this implisit yang melaluinya kita mengakses m_value.

Berikut urutan lengkap peristiwa.

  1. Di main, sebuah instans dari MyClass dibuat (myclass_instance).
  2. Objek async dibuat, menunjuk (melalui ini) ke myclass_instance.
  3. Fungsi winrt::Windows::Foundation::IAsyncAction::get mencapai titik suspensi pertamanya, blok selama beberapa detik, lalu mengembalikan hasil RetrieveValueAsync.
  4. RetrieveValueAsync mengembalikan nilai .this->m_value

Langkah 4 hanya aman selama ini tetap valid.

Tetapi bagaimana jika instans kelas dihancurkan sebelum operasi asinkron selesai? Instans kelas dapat keluar dari cakupan dengan berbagai cara sebelum metode asinkron selesai dieksekusi. Tetapi kita dapat mensimulasikannya dengan mengatur instans kelas ke 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;
}

Setelah kita memusnahkan instans kelas tersebut, tampaknya kita tidak lagi mereferensikannya secara langsung. Tetapi tentu saja objek asinkron memiliki penunjuk this, dan mencoba menggunakannya untuk menyalin nilai yang disimpan dalam instance kelas. Korutin merupakan fungsi anggota, dan mengasumsikan bahwa ia dapat menggunakan pointer this dengan leluasa.

Dengan perubahan ini pada kode, kami mengalami masalah di langkah 4, karena instans kelas telah dihancurkan, dan ini tidak lagi valid. Segera setelah objek asinkron mencoba mengakses variabel di dalam instans kelas, itu akan crash (atau melakukan sesuatu yang sama sekali tidak terdefinisi).

Solusinya adalah memberikan operasi asinkron—koroutine—referensi kuatnya sendiri ke instans kelas. Sebagaimana ditulis saat ini, coroutine secara efektif menyimpan pointer mentah this ke instance kelas; namun, hal itu tidak cukup untuk menjaga instance kelas tetap hidup.

Untuk menjaga instans kelas tetap hidup, ubah implementasi RetrieveValueAsync ke yang ditunjukkan di bawah ini.

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

Kelas C++/WinRT secara langsung atau tidak langsung berasal dari templat winrt::implements . Karena itu, objek C++/WinRT dapat memanggil fungsi anggota terlindung implements::get_strong untuk mengambil referensi kuat ke pointer this. Perhatikan bahwa tidak perlu benar-benar menggunakan strong_this variabel dalam contoh kode di atas; cukup memanggil get_strong meningkatkan jumlah referensi objek C++/WinRT, dan menjaga implisitnya agar pointer ini valid.

Important

Karena get_strong adalah fungsi anggota dari templat struct winrt::implements , Anda dapat memanggilnya hanya dari kelas yang secara langsung atau tidak langsung berasal dari winrt::implements, seperti kelas C++/WinRT. Untuk informasi selengkapnya tentang menurunkan dari winrt::implements, beserta contohnya, lihat Menulis API dengan C++/WinRT.

Ini menyelesaikan masalah yang sebelumnya kami miliki ketika kami sampai di langkah 4. Bahkan jika semua referensi lain ke instans kelas menghilang, koroutin telah mengambil tindakan pencegahan untuk menjamin bahwa dependensinya stabil.

Jika referensi yang kuat tidak sesuai, maka Anda dapat memanggil implements::get_weak untuk mengambil referensi yang lemah untuk ini. Cukup konfirmasikan bahwa Anda dapat mengambil referensi yang kuat sebelum mengakses ini. Sekali lagi, get_weak adalah fungsi anggota dari templat struct winrt::implements .

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

Dalam contoh di atas, referensi yang lemah tidak mencegah instans kelas dihancurkan ketika tidak ada referensi yang kuat yang tersisa. Tetapi ini memberi Anda cara untuk memeriksa apakah referensi yang kuat dapat diperoleh sebelum mengakses variabel anggota.

Mengakses pointer this secara aman menggunakan delegat penanganan peristiwa

Skenario

Untuk informasi umum tentang penanganan peristiwa, lihat Menangani peristiwa dengan menggunakan delegasi di C++/WinRT.

Bagian sebelumnya menyoroti potensi masalah siklus hidup dalam bidang coroutine dan konkurensi. Tetapi, jika Anda menangani peristiwa dengan fungsi anggota objek, atau dari dalam fungsi lambda di dalam fungsi anggota objek, maka Anda perlu memikirkan masa pakai relatif penerima peristiwa (objek yang menangani peristiwa) dan sumber peristiwa (objek yang meningkatkan peristiwa). Mari kita lihat beberapa contoh kode.

Daftar kode di bawah ini pertama-tama mendefinisikan kelas EventSource sederhana, yang meningkatkan peristiwa generik yang ditangani oleh delegasi apa pun yang telah ditambahkan ke dalamnya. Contoh kejadian ini kebetulan menggunakan jenis delegasi Windows::Foundation::EventHandler, tetapi masalah dan solusi yang dibahas di sini berlaku untuk semua jenis delegasi.

Kemudian, kelas EventRecipient menyediakan handler untuk eventSource::Event dalam bentuk fungsi lambda.

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

Polanya adalah penerima kejadian memiliki penangan kejadian lambda yang bergantung pada pointer this. Setiap kali penerima peristiwa memiliki masa hidup lebih lama daripada sumber peristiwa, ia juga memiliki masa hidup lebih lama daripada dependensi tersebut. Dan dalam kasus-kasus tersebut, yang sering terjadi, pola tersebut berfungsi dengan baik. Sebagian kasus ini sudah jelas, misalnya ketika halaman UI menangani kejadian yang dipicu oleh kontrol yang ada di halaman. Halaman keluar dari tombol—jadi, handler juga mengungguli tombol. Ini berlaku kapan saja penerima memiliki sumber (sebagai anggota data, misalnya), atau kapan saja penerima dan sumbernya adalah saudara kandung dan secara langsung dimiliki oleh beberapa objek lain.

Ketika Anda yakin bahwa Anda memiliki situasi di mana handler tidak akan berumur lebih panjang daripada this yang menjadi sandarannya, Anda dapat menangkap this seperti biasa, tanpa mempertimbangkan masa hidup kuat atau lemah.

Tetapi, masih ada kasus ketika this tidak tetap ada selama digunakan di dalam handler (termasuk handler untuk peristiwa penyelesaian dan kemajuan yang dipicu oleh aksi dan operasi asinkron), dan penting untuk mengetahui cara menanganinya.

  • Ketika sumber peristiwa menaikkan peristiwanya secara sinkron, Anda dapat mencabut handler Anda dan yakin bahwa Anda tidak akan menerima peristiwa lagi. Tetapi untuk peristiwa asinkron, bahkan setelah pembatalan dilakukan (dan terutama jika pembatalan dilakukan di dalam destruktor), peristiwa yang sedang diproses masih bisa sampai ke objek Anda setelah objek tersebut mulai dihancurkan. Menemukan tempat untuk berhenti berlangganan sebelum penghancuran dapat mengurangi masalah, tetapi terus membaca untuk solusi yang kuat.
  • Jika Anda membuat coroutine untuk mengimplementasikan metode asinkron, hal itu dimungkinkan.
  • Dalam kasus yang jarang terjadi dengan objek kerangka kerja UI XAML tertentu (SwapChainPanel, misalnya), hal ini dimungkinkan jika objek penerima difinalisasi tanpa membatalkan pendaftaran dari sumber peristiwa.

Masalah ini

Versi fungsi utama berikutnya ini mensimulasikan apa yang terjadi ketika penerima peristiwa dihancurkan (mungkin keluar dari cakupan) saat sumber peristiwa masih meningkatkan peristiwa.

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

Penerima event dihapus, tetapi event handler lambda di dalamnya masih berlangganan ke event Event. Ketika peristiwa tersebut dipicu, lambda berupaya mendeferensikan pointer this, yang pada saat itu sudah tidak valid. Jadi, pelanggaran akses terjadi akibat kode dalam handler (atau dalam kelanjutan koroutine) yang berupaya menggunakannya.

Important

Jika Anda menghadapi situasi seperti ini, Anda perlu mempertimbangkan masa hidup objek this; dan apakah objek this yang ditangkap memiliki masa hidup yang lebih panjang daripada capture tersebut atau tidak. Jika tidak, maka tangkap dengan referensi yang kuat atau lemah, seperti yang akan kami tunjukkan di bawah ini.

Atau—jika masuk akal untuk skenario Anda, dan jika pertimbangan thread memang memungkinkan—opsi lainnya adalah membatalkan pendaftaran handler setelah penerima selesai memproses event, atau dalam destruktor penerima. Lihat Mencabut delegasi terdaftar.

Ini adalah cara kami mendaftarkan handler.

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

Lambda secara otomatis menangkap variabel lokal apa pun secara referensi. Jadi, untuk contoh ini, kita juga bisa menuliskannya seperti ini.

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

Dalam kedua kasus, kita hanya menangkap pointer ini mentah. Dan itu tidak berpengaruh pada penghitungan referensi, jadi tidak ada yang mencegah objek saat ini dihancurkan.

Solusinya

Solusinya adalah menangkap referensi yang kuat (atau, seperti yang akan kita lihat, referensi yang lemah jika itu lebih tepat). Referensi yang kuat akan menaikkan jumlah referensi, dan memang mempertahankan objek saat ini tetap aktif. Anda cukup mendeklarasikan variabel tangkapan (disebut strong_this dalam contoh ini), dan menginisialisasinya dengan pemanggilan ke implements::get_strong, yang mengambil referensi kuat ke pointer this.

Important

Karena get_strong adalah fungsi anggota dari templat struct winrt::implements , Anda dapat memanggilnya hanya dari kelas yang secara langsung atau tidak langsung berasal dari winrt::implements, seperti kelas C++/WinRT. Untuk informasi selengkapnya tentang menurunkan dari winrt::implements, beserta contohnya, lihat Menulis API dengan C++/WinRT.

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

Anda bahkan dapat menghilangkan penangkapan otomatis objek saat ini, dan mengakses anggota data melalui variabel tangkapan alih-alih melalui this implisit.

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

Jika referensi yang kuat tidak sesuai, maka Anda dapat memanggil implements::get_weak untuk mengambil referensi yang lemah untuk ini. Referensi lemah tidak mempertahankan objek saat ini agar tetap ada. Jadi, cukup konfirmasikan bahwa Anda masih dapat mengambil referensi yang kuat dari referensi yang lemah sebelum mengakses anggota.

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

Jika Anda menangkap pointer mentah, Anda harus memastikan objek yang ditunjuk tetap hidup.

Jika Anda menggunakan fungsi anggota sebagai delegasi

Selain fungsi lambda, prinsip-prinsip ini juga berlaku saat menggunakan fungsi anggota sebagai delegasi. Sintaksnya berbeda, jadi mari kita lihat beberapa kode. Pertama, berikut adalah penanganan aktivitas fungsi anggota yang berpotensi tidak aman, menggunakan pointer ini mentah.

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

Ini adalah cara standar dan konvensional untuk merujuk ke objek dan fungsi anggotanya. Untuk membuatnya aman, Anda dapat—mulai versi 10.0.17763.0 (Windows 10, versi 1809) dari Windows SDK—buat referensi yang kuat atau lemah pada titik di mana handler terdaftar. Pada titik itu, objek penerima peristiwa diketahui masih hidup.

Untuk referensi yang kuat, cukup panggil get_strong menggantikan pointer ini mentah. C++/WinRT memastikan bahwa delegat yang dihasilkan memegang referensi yang kuat ke objek saat ini.

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

Menyimpan referensi yang kuat berarti objek Anda baru dapat dihancurkan setelah handler dibatalkan pendaftarannya dan semua callback yang masih berjalan telah selesai. Namun, jaminan tersebut hanya berlaku pada saat peristiwa itu dipicu. Jika penangan peristiwa Anda bersifat asinkron, Anda harus memberikan referensi yang kuat ke instans kelas kepada coroutine Anda sebelum titik penangguhan pertama (untuk detail dan kode, lihat bagian Mengakses pointer this dengan aman dalam coroutine anggota kelas sebelumnya di topik ini). Tetapi itu membuat referensi melingkar antara sumber peristiwa dan objek Anda, jadi Anda perlu secara eksplisit memutusnya dengan mencabut peristiwa Anda.

Untuk referensi yang lemah, panggil get_weak. C++/WinRT memastikan delegat yang dihasilkan memiliki referensi lemah. Pada menit terakhir, dan di belakang layar, delegasi mencoba menyelesaikan referensi lemah ke yang kuat, dan hanya memanggil fungsi anggota jika berhasil.

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

Jika delegasi memanggil fungsi anggota Anda, C++/WinRT akan menjaga objek Anda tetap hidup sampai handler Anda kembali. Namun, jika handler Anda bersifat asinkron, handler tersebut akan mengembalikan kontrol pada titik-titik suspensi, sehingga Anda harus memberikan referensi yang kuat dari coroutine Anda ke instance kelas sebelum titik suspensi pertama. Sekali lagi, untuk informasi selengkapnya, lihat Mengakses pointer ini dengan aman di bagian coroutine anggota kelas sebelumnya dalam topik ini.

Jika fungsi anggota bukan bagian dari tipe Windows Runtime

Ketika metode get_strong tidak tersedia untuk Anda (jenis Anda bukan jenis Windows Runtime), Anda dapat menggunakan teknik yang ditunjukkan dalam contoh kode di bawah ini. Di sini, kelas C++ reguler (bernama ConsoleNetworkWatcher) ditampilkan menangani peristiwa NetworkInformation.NetworkStatusChanged .

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

Contoh referensi yang lemah menggunakan SwapChainPanel::CompositionScaleChanged

Dalam contoh kode ini, kita menggunakan kejadian SwapChainPanel::CompositionScaleChanged sebagai ilustrasi lain tentang referensi lemah. Kode ini mendaftarkan penanganan aktivitas menggunakan lambda yang menangkap referensi lemah kepada penerima.

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

Dalam klausa penangkapan lambda, sebuah variabel sementara dibuat, yang merepresentasikan referensi lemah ke this. Dalam badan lambda, jika referensi kuat ke this dapat diperoleh, maka fungsi OnCompositionScaleChanged dipanggil. Dengan begitu, di dalam OnCompositionScaleChanged, ini dapat digunakan dengan aman.

Referensi lemah dalam C++/WinRT

Di atas, kita melihat referensi lemah yang digunakan. Secara umum, ini berguna untuk memutus referensi siklis. Misalnya, untuk implementasi asli kerangka kerja UI berbasis XAML—karena desain historis kerangka kerja—mekanisme referensi yang lemah di C++/WinRT diperlukan untuk menangani referensi siklik. Namun, di luar XAML, Anda kemungkinan tidak perlu menggunakan referensi lemah (bukan berarti referensi tersebut secara inheren bersifat khusus untuk XAML). Sebaliknya Anda harus, lebih sering daripada tidak, dapat merancang API C++/WinRT Anda sendiri sedemikian rupa untuk menghindari kebutuhan akan referensi siklik dan referensi yang lemah.

Untuk tipe apa pun yang Anda deklarasikan, tidak langsung jelas bagi C++/WinRT apakah referensi lemah diperlukan, atau kapan referensi tersebut diperlukan. Jadi, C++/WinRT menyediakan dukungan referensi yang lemah secara otomatis pada templat struct winrt::implements, dari mana jenis C++/WinRT Anda sendiri secara langsung atau tidak langsung berasal. Ini bersifat pay-for-play, artinya tidak menimbulkan biaya apa pun kecuali objek Anda benar-benar diminta untuk IWeakReferenceSource. Dan Anda dapat memilih secara eksplisit untuk menolak dukungan tersebut.

Contoh kode

Templat struct winrt::weak_ref adalah salah satu opsi untuk mendapatkan referensi lemah ke instans kelas.

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

Atau, Anda dapat menggunakan fungsi pembantu winrt::make_weak .

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

Membuat referensi yang lemah tidak memengaruhi jumlah referensi pada objek itu sendiri; itu hanya menyebabkan blok kontrol dialokasikan. Blok kontrol itu mengurus penerapan semantik referensi yang lemah. Anda kemudian dapat mencoba mempromosikan referensi yang lemah ke referensi yang kuat dan, jika berhasil, gunakan.

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

Asalkan beberapa referensi kuat lainnya masih ada, weak_ref::get call menaikkan jumlah referensi dan mengembalikan referensi yang kuat ke pemanggil.

Menolak dukungan referensi yang lemah

Dukungan referensi yang lemah bersifat otomatis. Tetapi Anda dapat memilih secara eksplisit untuk menolak dukungan tersebut dengan meneruskan struct penanda winrt::no_weak_ref sebagai argumen templat ke kelas dasar Anda.

Jika Anda memperoleh langsung dari winrt::implements.

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

Jika Anda membuat kelas runtime.

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

Tidak masalah di mana dalam paket parameter variadik struktur penanda muncul. Jika Anda meminta referensi lemah untuk tipe yang dikecualikan, kompilator akan menampilkan "Ini hanya untuk dukungan referensi lemah".

API penting