Bagikan melalui


Referensi yang kuat dan lemah dalam C++/WinRT

Windows Runtime adalah sistem yang dihitung referensi; dan dalam sistem seperti itu penting bagi Anda untuk mengetahui tentang signifikansi, dan perbedaan antara, referensi yang kuat dan lemah (dan referensi yang tidak ada, seperti implisit pointer ini ). 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 memiliki dukungan mendalam dalam proyeksi bahasa, C++/WinRT bertemu Anda setengah dalam pekerjaan Anda membangun sistem yang lebih kompleks dengan sederhana dan benar.

Catatan

Hanya dengan beberapa pengecualian, dukungan referensi lemah aktif secara default untuk jenis Windows Runtime yang Anda gunakan atau penulis di C++/WinRT. Windows.UI.Composition dan Windows.Devices.Input.PenDevice adalah contoh pengecualian—yaitu, namespace di mana dukungan referensi yang lemah tidak aktif untuk jenis tersebut. Lihat juga Apakah delegasi pencabutan otomatis Anda gagal mendaftar.

Jika Anda menulis jenis, lihat bagian Referensi lemah di C++/WinRT dalam topik ini.

Brankas mengakses penunjuk ini dalam koroutin anggota kelas

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

Daftar kode di bawah ini menunjukkan contoh umum koroutine yang merupakan fungsi anggota kelas. Anda dapat menyalin-tempel contoh ini ke dalam file yang ditentukan dalam proyek Aplikasi Konsol Windows (C++/WinRT) baru.

// 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 sinkron hingga titik penangguhan pertama, di mana kontrol dikembalikan ke pemanggil. Di RetrieveValueAsync, yang pertama co_await adalah titik suspensi pertama. Pada saat coroutine dilanjutkan (sekitar lima detik kemudian, dalam hal ini), apa pun mungkin terjadi pada penunjuk ini implisit tempat kita mengakses m_value.

Berikut urutan lengkap peristiwa.

  1. Utamanya, instans 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, memblokir 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? Ada semua jenis cara instans kelas dapat keluar dari cakupan sebelum metode asinkron selesai. 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 titik di mana kita menghancurkan instans kelas, sepertinya kita tidak langsung merujuknya lagi. Tetapi tentu saja objek asinkron memiliki penunjuk ini , dan mencoba menggunakannya untuk menyalin nilai yang disimpan di dalam instans kelas. Coroutine adalah fungsi anggota, dan mengharapkan untuk dapat menggunakan pointer ini dengan impunitas.

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. Seperti yang ditulis saat ini, coroutine secara efektif memegang pointer ini mentah ke instans kelas; tetapi itu tidak cukup untuk menjaga instans 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 implementasinya::get_strong fungsi anggota yang dilindungi untuk mengambil referensi yang kuat ke pointer ini. 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.

Penting

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 mendapatkan dari winrt::implements, dan contoh, lihat API Penulis 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.

Brankas mengakses pointer ini dengan delegasi penanganan peristiwa

Skenario

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

Bagian sebelumnya menyoroti potensi masalah masa pakai di area koroutin 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 perbaikan di sini berlaku untuk setiap dan 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 bahwa penerima acara memiliki penanganan aktivitas lambda dengan dependensi pada penunjuk ini . Setiap kali penerima peristiwa keluar dari sumber peristiwa, itu keluar dari dependensi tersebut. Dan dalam kasus-kasus tersebut, yang umum, pola bekerja dengan baik. Beberapa kasus ini jelas, seperti ketika halaman UI menangani peristiwa yang dinaikkan 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 memiliki kasus di mana handler tidak akan hidup lebih lama dari ini yang bergantung padanya, maka Anda dapat menangkap ini secara normal, tanpa pertimbangan untuk masa pakai yang kuat atau lemah.

Tetapi masih ada kasus di mana ini tidak melampaui penggunaannya dalam handler (termasuk handler untuk penyelesaian dan peristiwa kemajuan yang diangkat oleh tindakan 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 mencabut (dan terutama ketika mencabut dalam destruktor), peristiwa dalam penerbangan mungkin mencapai objek Anda setelah mulai merusak. Menemukan tempat untuk berhenti berlangganan sebelum penghancuran dapat mengurangi masalah, tetapi terus membaca untuk solusi yang kuat.
  • Jika Anda menulis koroutine untuk menerapkan metode asinkron, maka itu mungkin.
  • Dalam kasus yang jarang terjadi dengan objek kerangka kerja UI XAML tertentu (SwapChainPanel, misalnya), maka itu mungkin, jika penerima diselesaikan 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 peristiwa dihancurkan, tetapi penanganan aktivitas lambda di dalamnya masih berlangganan peristiwa Peristiwa . Ketika peristiwa itu dinaikkan, lambda mencoba untuk mendereferensikan pointer ini , yang pada saat itu tidak valid. Jadi, pelanggaran akses dihasilkan dari kode di handler (atau dalam kelanjutan koroutine) yang mencoba menggunakannya.

Penting

Jika Anda mengalami situasi seperti ini, maka Anda harus memikirkan masa pakai objek ini; dan apakah objek ini yang ditangkap keluar dari tangkapan 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 utas memungkinkan—maka opsi lain adalah mencabut handler setelah penerima selesai dengan peristiwa, atau di 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 mengambil variabel lokal apa pun dengan referensi. Jadi, untuk contoh ini, kita bisa secara setara telah menulis 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 memang menaikkan jumlah referensi, dan itu menjaga objek saat ini tetap hidup. Anda hanya mendeklarasikan variabel pengambilan (disebut strong_this dalam contoh ini), dan menginisialisasinya dengan panggilan untuk mengimplementasikan::get_strong, yang mengambil referensi yang kuat ke pointer ini.

Penting

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 mendapatkan dari winrt::implements, dan contoh, lihat API Penulis dengan C++/WinRT.

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

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

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 menjaga objek saat ini tetap hidup. 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, maka Anda harus memastikan anda menjaga objek pointed-to tetap hidup.

Jika Anda menggunakan fungsi anggota sebagai delegasi

Selain fungsi lambda, prinsip-prinsip ini juga berlaku untuk menggunakan fungsi anggota sebagai delegasi Anda. 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 membuat ini aman, Anda dapat —mulai dari versi 10.0.17763.0 (Windows 10, versi 1809) dari Windows SDK—membuat 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 delegasi yang dihasilkan menyimpan referensi yang kuat ke objek saat ini.

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

Menangkap referensi yang kuat berarti objek Anda akan memenuhi syarat untuk penghancuran hanya setelah handler tidak terdaftar dan semua panggilan balik yang luar biasa telah kembali. Namun, jaminan tersebut hanya berlaku pada saat acara dinaikkan. Jika penanganan aktivitas Anda tidak sinkron, maka Anda harus memberi koroutin referensi yang kuat ke instans kelas sebelum titik penangguhan pertama (untuk detail, dan kode, lihat Brankas mengakses penunjuk ini di bagian koroutine anggota kelas sebelumnya dalam 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 bahwa delegasi yang dihasilkan menyimpan referensi yang 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 asinkron, maka akan kembali pada titik suspensi, sehingga Anda harus memberi koroutin referensi yang kuat ke instans kelas sebelum titik penangguhan pertama. Sekali lagi, untuk informasi selengkapnya, lihat Brankas mengakses penunjuk ini di bagian koroutine anggota kelas sebelumnya dalam topik ini.

Jika fungsi anggota bukan milik jenis 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 peristiwa SwapChainPanel::CompositionScaleChanged dengan cara ilustrasi lain dari referensi yang lemah. Kode ini mendaftarkan penanganan aktivitas menggunakan lambda yang menangkap referensi lemah kepada penerima.

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

Dalam klausa tangkapan lamba, variabel sementara dibuat, mewakili referensi lemah untuk ini. Dalam isi lambda, jika referensi yang kuat untuk ini 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, mereka baik untuk melanggar referensi siklik. 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 mungkin tidak perlu menggunakan referensi yang lemah (bukan berarti ada sesuatu yang secara inheren khusus XAML tentang mereka). 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 jenis tertentu yang Anda nyatakan, tidak segera jelas untuk C++/WinRT apakah atau ketika referensi lemah 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 adalah bayar untuk bermain, karena tidak dikenakan biaya apa pun kecuali objek Anda benar-benar dikueri 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 menambahkan 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 menulis 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 jenis opted-out, maka compiler akan membantu Anda dengan "Ini hanya untuk dukungan ref yang lemah".

API penting