C++/WinRT教程(第四篇)WinRT 的錯誤和異常處理

目錄

前言

避免捕獲和拋出異常

捕獲異常

拋出異常

編輯API時拋出異常

使用 noexcept 時如何調試

調用同步代碼

快速失敗

斷言


前言

本文主要介紹?C++/WinRT?中的異常如何使用以及使用原則,如果你剛開始接觸WinRT,建議先閱讀第一篇。

C++/WinRT教程(第一篇)-CSDN博客

C++/WinRT教程(第二篇)基礎類型的使用-CSDN博客

C++/WinRT教程(第三篇)API的使用-CSDN博客

其他資料:

現代 C++ 處理異常和錯誤的最佳做法 | Microsoft Learn

操作說明:異常安全性設計 | Microsoft Learn

避免捕獲和拋出異常

最好盡量避免捕獲和拋出異常。 如果沒有異常處理程序,Windows 將自動生成錯誤報告(包括故障的小型轉儲),以便跟蹤問題所在位置。

應僅在發生意外運行時錯誤時拋出異常,并處理帶有錯誤/結果代碼的任何其他事項,直接并靠近故障原因。 這樣,當異常“被”引發時,你會知道原因是代碼中的 bug 還是系統中的異常錯誤狀態。

例如訪問 Windows 注冊表的場景。 如果你的應用無法從注冊表讀取值,這是預料之中的,你應該正確處理。 不要拋出異常;而應返回?bool?或?enum?值指示未讀取值或原因。 另一方面,無法向注冊表寫入值很可能表示你的應用程序中存在的問題更大

拋出異常異常往往會比使用錯誤代碼更慢。谷歌和微軟代碼規范都不提倡使用異常。

捕獲異常

在?Windows 運行時 ABI?層出現的錯誤狀態以 HRESULT 值的形式返回。 不過你無需處理代碼中的 HRESULT。 為每個使用方的 API 生成的 C++/WinRT 投影代碼將檢測 ABI 層的錯誤 HRESULT 代碼,并將代碼轉換為你可以捕獲并處理的?winrt::hresult_error?異常。 如果你的確希望處理 HRESULTS,那么請使用“winrt::hresult”類型。

例如,如果用戶碰巧,在你的應用程序迭代圖片庫時,從該集合中刪除了圖像,那么投影將拋出異常。 這是你必須捕獲和處理該異常的一種情況。 下面的代碼示例展示了這種情況。

#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.Storage.h>
#include <winrt/Windows.UI.Xaml.Media.Imaging.h>using namespace winrt;
using namespace Windows::Foundation;
using namespace Windows::Storage;
using namespace Windows::UI::Xaml::Media::Imaging;IAsyncAction MakeThumbnailsAsync()
{auto imageFiles{ co_await KnownFolders::PicturesLibrary().GetFilesAsync() };for (StorageFile const& imageFile : imageFiles){BitmapImage bitmapImage;try{auto thumbnail{ co_await imageFile.GetThumbnailAsync(FileProperties::ThumbnailMode::PicturesView) };if (thumbnail) bitmapImage.SetSource(thumbnail);}catch (winrt::hresult_error const& ex){winrt::hresult hr = ex.code(); // HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND).winrt::hstring message = ex.message(); // The system cannot find the file specified.}}
}

請在調用?co_await?的函數時在協調程序中使用相同模式。 此 HRESULT 到異常轉換的另一個示例是,當組件 API 返回 E_OUTOFMEMORY 時,會導致拋出“std::bad_alloc”。

如果只是要瀏覽 HRESULT 代碼,則首選?winrt::hresult_error::code。 另一方面,winrt::hresult_error::to_abi?函數轉換為 COM 錯誤對象,并將狀態推送到 COM 線程本地存儲。

拋出異常

注:慎重,沒捕獲成功你的程序會原地崩潰

下方代碼示例使用?winrt::handle?值作為從?CreateEvent?返回的 HANDLE 的包裝 。 然后將該句柄(從其創建?bool?值)傳遞到?winrt::check_bool?函數模板。

?“winrt::check_bool”使用?bool?或任何可轉換為?false(錯誤條件)或?true(成功條件)的值。

winrt::handle h{ ::CreateEvent(nullptr, false, false, nullptr) };
winrt::check_bool(bool{ h });
winrt::check_bool(::SetEvent(h.get()));

如果你傳遞到?winrt::check_bool?的值為 false,那么以下操作序列將生效。

  • “winrt::check_bool”調用?winrt::throw_last_error?函數 。
  • “winrt::throw_last_error”調用?GetLastError?來檢索調用線程的最后一個錯誤代碼值,然后調用?winrt::throw_hresult?函數 。
  • “winrt::throw_hresult”使用表示該錯誤代碼的?winrt::hresult_error?對象(或標準對象)拋出異常 。

由于 Windows API 使用各種返回值類型報告運行時的錯誤,因此除“winrt::check_bool”外,還有其他一些用于檢查值和拋出異常的有用的幫助程序函數。

  • winrt::check_hresult。 檢查 HRESULT 代碼是否表示錯誤,如果是,則調用“winrt::throw_hresult”。
  • winrt::check_nt。 檢查代碼是否表示錯誤,如果是,則調用“winrt::throw_hresult”。
  • winrt::check_pointer。 檢查指針是否為 null,如果是,則調用“winrt::throw_last_error”。
  • winrt::check_win32。 檢查代碼是否表示錯誤,如果是,則調用“winrt::throw_hresult”。

你可以對常見的返回代碼類型使用這些幫助程序函數,也可以響應任何錯誤條件并調用?winrt::throw_last_error?或?winrt::throw_hresult?。

編輯API時拋出異常

所有?Windows 運行時應用程序二進制接口邊界(簡稱 ABI 邊界)必須為 noexcept,即不得有異常。 創作 API 時,應始終使用 C++?noexcept?關鍵字來標記 ABI 邊界。?noexcept?在 C++ 中有特定的行為。 如果 C++ 異常遇到?noexcept?邊界,則會調用?std::terminate,導致進程很快失敗。

該行為通常是理想的做法,因為未經處理的異常幾乎總是意味著進程中出現了未知狀態。

由于異常不得跨過 ABI 邊界,在實現中出現的錯誤條件以 HRESULT 錯誤代碼的形式跨 ABI 層返回。 在使用 C++/WinRT 創作 API 時,將生成代碼以供你將在實現中拋出的任何異常轉換為 HRESULT。?Winrt::to_hresult?函數以與此類似的模式用于生成的代碼。

HRESULT DoWork() noexcept
{try{// Shim through to your C++/WinRT implementation.return S_OK;}catch (...){return winrt::to_hresult(); // Convert any exception to an HRESULT.}
}

winrt::to_hresult?處理派生自 std::exception 和?winrt::hresult_error?及其派生類型的異常 。 在你的實現中,最好使用 winrt::hresult_error 或派生類型,以便你的 API 的使用者可以收到豐富的錯誤信息。 “std::exception”(映射到 E_FAIL)在你使用標準模板庫時引發異常的情況下受支持。

注:如果捕獲std::exception就捕獲不到?winrt::hresult_error?,所以最好就使用winrt::to_hresult?

使用 noexcept 時如何調試

如前所述,如果 C++ 異常遇到?noexcept?邊界,則會調用?std::terminate,導致進程很快失敗。 這不適用于調試,因為?std::terminate?通常會失去引發的大部分或所有錯誤或異常上下文,尤其是在涉及協同程序的情況下。

因此,本部分處理的是 ABI 方法(已使用?noexcept?進行適當的批注)使用?co_await?來調用異步 C++/WinRT 投影代碼的情況。

建議將對 C++/WinRT 項目代碼的調用包裝在?winrt::fire_and_forget?中。 這樣做就可以在正確的位置將未經處理的異常正確記錄為存放異常,大大提高可調試性。

HRESULT MyWinRTObject::MyABI_Method() noexcept
{winrt::com_ptr<Foo> foo{ get_a_foo() };[/*no captures*/](winrt::com_ptr<Foo> foo) -> winrt::fire_and_forget{co_await winrt::resume_background();foo->ABICall();AnotherMethodWithLotsOfProjectionCalls();}(foo);return S_OK;
}

winrt::fire_and_forget?有內置的?unhandled_exception?方法幫助程序,該程序調用?winrt::terminate,后者又調用?RoFailFastWithErrorContext。 這樣就可以保證任何上下文(存放異常、錯誤代碼、錯誤消息、堆棧回溯等)都會得到保存,不管是進行實時調試,還是進行事后轉儲。 為了方便起見,可以將“發后不理”部分重構成一個單獨的可返回?winrt::fire_and_forget?的函數,然后調用它。

調用同步代碼

在某些情況下,ABI 方法(同樣已使用?noexcept?進行適當的批注)僅調用同步代碼。 換而言之,它從不使用?co_await,不管是用來調用異步 Windows 運行時方法,還是用來在前臺和后臺線程之間切換。 在這種情況下,“?winrt::fire_and_forget”方法仍可使用,但效率不高。 可以改為執行類似下面的代碼。?

HRESULT abi() noexcept try
{// ABI code goes here.
} catch (...) { winrt::terminate(); }

快速失敗

上一部分的代碼仍會快速失敗。 從編寫的內容來看,該代碼不處理任何異常。 任何未經處理的異常都會導致程序終止。

但該形式是很好的,因為它確保了可調試性。 在罕見情況下,可能需要使用?try/catch,并處理某些異常。 但這應該很罕見,因為正如本主題所述,我們反對將異常作為一種流控制機制用于預期的條件。

記住,讓未經處理的異常逃脫無包裝的?noexcept?上下文是很糟糕的做法。 在該條件下,C++ 運行時會?std::terminate?進程,因此會失去任何存放的由 C++/WinRT 仔細記錄的異常信息。

斷言

對應用程序中的內部假設,存在斷言。 最好盡可能地為編譯時驗證使用“static_assert”。

WinRT使用帶布爾值表達式的?WINRT_ASSERTWINRT_ASSERT?是宏定義,并且擴展到?_ASSERTE。

WINRT_ASSERT(pos < size());

?WINRT_ASSERT 在發布版本中被編譯; 在調試版本中,它會在斷言所在的代碼行上停止調試器中的應用程序。

?不應在析構函數中使用異常。 因此,至少在調試版本中,你可以斷言從帶有 WINRT_VERIFY(帶有布爾值表達式)和 WINRT_VERIFY_(帶有預期結果和布爾值表達式)的析構函數調用函數的結果。

WINRT_VERIFY(::CloseHandle(value));
WINRT_VERIFY_(TRUE, ::CloseHandle(value));

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/712019.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/712019.shtml
英文地址,請注明出處:http://en.pswp.cn/news/712019.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

67-箭頭函數,new.target,模版字符串

1.箭頭函數 ES6新增語法&#xff0c;用來簡化函數的書寫()>{} <script>//箭頭函數的基本使用let a (a,b)>{return ab;}let c a(1,2);console.log(c);//輸出3</script> 2.簡寫形式&#xff1a; 2.1參數&#xff1a;只有一個參數時可以省略小括號a>{}&…

面試經典 150 題 ---- 輪轉數組

面試經典 150 題 ---- 輪轉數組 輪轉數組方法一&#xff1a;使用額外的數組方法二&#xff1a;數組翻轉 輪轉數組 方法一&#xff1a;使用額外的數組 我們可以使用額外的數組來將每個元素放至正確的位置。用 n 表示數組的長度&#xff0c;我們遍歷原數組&#xff0c;將原數組…

Java底層自學大綱_JVM篇

JVM專題_自學大綱所屬類別學習主題建議課時&#xff08;h&#xff09; A 深入理解Java虛擬機001 JVM類加載器設計原理2.5 A 深入理解Java虛擬機002 基于SPI破解雙親委派機制2.5 A 深入理解Java虛擬機003 JVM內部結構分析2.5 A 深入理解Java虛擬機004 字符串常量池原理2.5 …

【算法】長短期記憶網絡(LSTM,Long Short-Term Memory)

這是一種特殊的循環神經網絡&#xff0c;能夠學習數據中的長期依賴關系&#xff0c;這是因為模型的循環模塊具有相互交互的四個層的組合&#xff0c;它可以記憶不定時間長度的數值&#xff0c;區塊中有一個gate能夠決定input是否重要到能被記住及能不能被輸出output。 原理 黃…

37.云原生之springcloud+k8s+GitOps+istio+安全實踐

云原生專欄大綱 文章目錄 準備工作項目結構介紹配置安全測試ConfigMapSecret使用Secret中數據的方式Deployment使用Secret配置Secret加密 kustomize部署清單ConfigMap改造SecretSealedSecretDeployment改造Serviceistio相關資源DestinationRuleGatewayVirtualServiceServiceAc…

132557-72-3,2,3,3-三甲基-3H-吲哚-5-磺酸,具有優異的反應活性和光學性能

132557-72-3&#xff0c;5-Sulfo-2,3,3-trimethyl indolenine sodium salt&#xff0c;2,3,3-三甲基-3H-吲哚-5-磺酸&#xff0c;具有優異的反應活性和光學性能&#xff0c;一種深棕色粉末 您好&#xff0c;歡迎來到新研之家 文章關鍵詞&#xff1a;132557-72-3&#xff0c;5…

ROS2體系框架

文章目錄 1.ROS2的系統架構2.ROS2的編碼風格3.細談初始化和資源釋放4.細談配置文件5.ROS2的一些命令6.ROS2的核心模塊6.1 通信模塊6.2 功能包6.3 分布式6.4 終端命令和rqt6.5 launch6.6 TF坐標變換6.7 可視化RVIZ 1.ROS2的系統架構 開發者的工作內容一般都在應用層&#xff0c;…

MySQL學習Day24—數據庫的設計規范

一、數據庫設計的重要性: 1.糟糕的數據庫設計產生的問題: (1)數據冗余、信息重復、存儲空間浪費 (2)數據更新、插入、刪除的異常 (3)無法正確表示信息 (4)丟失有效信息 (5)程序性能差 2.良好的數據庫設計有以下優點: (1)節省數據的存儲空間 (2)能夠保證數據的完整性 …

力扣138.隨機鏈表的復制

給你一個長度為 n 的鏈表&#xff0c;每個節點包含一個額外增加的隨機指針 random &#xff0c;該指針可以指向鏈表中的任何節點或空節點。 構造這個鏈表的 深拷貝。 深拷貝應該正好由 n 個 全新 節點組成&#xff0c;其中每個新節點的值都設為其對應的原節點的值。新節點的 n…

編寫一個自動合并代碼到不同分支的腳本小工具

新建一個 autoMerge.sh 的文件&#xff0c;文件內容如下 # 提示用戶確認繼續執行 read -p "確認要執行腳本嗎&#xff1f;(輸入 yes 繼續): " userInput# 檢查用戶輸入是否為 "yes" if [ "$userInput" ! "yes" ]; thenecho "用戶…

《TCP/IP詳解 卷一》第9章 廣播和組播

目錄 9.1 引言 9.2 廣播 9.2.1 使用廣播地址 9.2.2 發送廣播數據報 9.3 組播 9.3.1 將組播IP地址轉換為組播MAC地址 9.3.2 例子 9.3.3 發送組播數據報 9.3.4 接收組播數據報 9.3.5 主機地址過濾 9.4 IGMP協議和MLD協議 9.4.1 組成員的IGMP和MLD處理 9.4.2 組播路由…

可用于智能客服的完全開源免費商用的知識庫項目

介紹 FastWiki項目是一個高性能、基于最新技術棧的知識庫系統&#xff0c;專為大規模信息檢索和智能搜索設計。利用微軟Semantic Kernel進行深度學習和自然語言處理&#xff0c;結合.NET 8和MasaBlazor前端框架&#xff0c;后臺采用.NET 8MasaFrameworkSemanticKernel&#xff…

嵌入式Linux學習DAY26

管道的作用&#xff1a;進程間的通信 無名管道&#xff1a; 只能在父子進程中進行通信 pipe int pipe(int pipefd[2]); 功能: 創建一個無名管道 參數: pipefd[0]:讀管道文件描述符 pipefd[1]:寫管道文件描述符 …

【InternLM 實戰營筆記】基于 InternLM 和 LangChain 搭建MindSpore知識庫

InternLM 模型部署 準備環境 拷貝環境 /root/share/install_conda_env_internlm_base.sh InternLM激活環境 conda activate InternLM安裝依賴 # 升級pip python -m pip install --upgrade pippip install modelscope1.9.5 pip install transformers4.35.2 pip install str…

【大廠AI課學習筆記NO.53】2.3深度學習開發任務實例(6)數據采集

這個系列寫了53期了&#xff0c;很多朋友收藏&#xff0c;看來還是覺得有用。 后續我會把相關的內容&#xff0c;再次整理&#xff0c;做成一個人工智能專輯。 今天學習到了數據采集的環節。 這里有個問題&#xff0c;數據準備包括什么&#xff0c;還記得嗎&#xff1f; 數…

ZStack Cube超融合入選IDC《中國超融合基礎架構市場評估》報告

近日&#xff0c;IDC發布了《中國超融合基礎架構市場評估&#xff0c;2023》。IDC針對中國超融合基礎架構市場的發展現狀展開了調研&#xff0c;明確了最終用戶構建融合型云平臺的痛點和難點&#xff0c;闡述了市場中各技術服務提供商的服務方案和優勢&#xff0c;并對未來中國…

vue3+ts+vite數據大屏自適應總結(兩種方法)

總結一下我常用的數據大屏自適應方法 目錄 1、通過css縮放方案&#xff1a; 利用transform&#xff1a;scale 進行適配2、采用rem布局&#xff0c; 根據屏幕分辨率大小不同&#xff0c;調整根元素html的font-size&#xff0c; 從而達到每個元素寬高自動變化&#xff0c;適配不…

接口測試實戰--mock測試、日志模塊

一、mock測試 在前后端分離項目中,當后端工程師還沒有完成接口開發的時候,前端開發工程師利用Mock技術,自己用mock技術先調用一個虛擬的接口,模擬接口返回的數據,來完成前端頁面的開發。 接口測試和前端開發有一個共同點,就是都需要用到后端工程師提供的接口。所以,當…

Redis速學

一、介紹Redis 基本概念和特點 Redis是一個開源的內存數據庫&#xff0c;它主要用于數據緩存和持久化。其數據存儲在內存中&#xff0c;這使得它具有非常快的讀寫速度。Redis支持多種數據結構&#xff0c;包括字符串、哈希、列表、集合和有序集合&#xff0c;這使得它非常靈活…

書生·浦語大模型圖文對話Demo搭建

前言 本節我們先來搭建幾個Demo來感受一下書生浦語大模型 InternLM-Chat-7B 智能對話 Demo 我們將使用 InternStudio 中的 A100(1/4) 機器和 InternLM-Chat-7B 模型部署一個智能對話 Demo 環境準備 在 InternStudio 平臺中選擇 A100(1/4) 的配置&#xff0c;如下圖所示鏡像…