当前位置: 首页 > news >正文

使用 C++/WinRT 的错误处理

本主题讨论了处理使用 C++/WinRT 编程时出现的错误的策略。 更多常规信息和背景,请参阅错误和异常处理 (Modern C++)。

避免捕获和抛出异常

建议继续编写异常安全代码,但最好尽量避免捕获和抛出异常。 如果没有异常处理程序,Windows 将自动生成错误报告(包括故障的小型转储),以便跟踪问题所在位置。

不要引发你预计会捕获的异常。 也不要使用预期会失败的异常。 应“仅在发生意外运行时错误时”抛出异常,并处理带有错误/结果代码的任何其他事项,直接并靠近故障原因。 这样,当异常“被”引发时,你会知道原因是代码中的 bug 还是系统中的异常错误状态。

考虑访问 Windows 注册表的场景。 如果你的应用无法从注册表读取值,这是预料之中的,你应该正确处理。 不要抛出异常;而应返回 bool 或 enum 值指示未读取值或原因。 另一方面,无法向注册表写入值很可能表示你的应用程序中存在的问题更大,是你无法明智处理的。 在这种情况下,你不希望应用程序继续,所以导致生成错误报告的异常是阻止应用程序造成任何损害的最快方式。

另一个示例中,请考虑从对 StorageFile.GetThumbnailAsync 的调用检索缩略图图像,然后将该缩略图传递到 BitmapSource.SetSourceAsync。 如果该调用顺序导致你将 nullptr 传递到 SetSourceAsync(无法读取图像文件;或许是文件扩展名使它看似包含图像数据,而实际并非如此),那么你将会导致引发无效的指针异常。 如果你发现自己代码存在这类情况,则不应将这种情况作为异常捕获和处理,而应检查从 GetThumbnailAsync 返回的 nullptr

抛出异常异常往往会比使用错误代码更慢。 如果你仅在出现严重错误时抛出异常,如果一切都正常运行,那么你永远不需要在性能方面妥协。

但更有可能的是,性能下降需要付出运行时开销来确保在不太可能抛出异常的情况下调用相应的析构函数。 这种保障成本不论实际是否抛出异常都会产生。 因此,你应该确保编译器清楚地了解哪些功能可以有抛出异常的可能性。 如果编译器可以证明某些功能不会引发任何异常(noexcept 规范),那么它可以优化所生成的代码。

捕获异常

在 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)在你使用标准模板库时引发异常的情况下受支持。

使用 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 运行时方法,还是用来在前台和后台线程之间切换。 在这种情况下,“发后不理”方法仍可使用,但效率不高。 可以改为执行类似下面的代码。

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

快速失败

上一部分的代码仍会快速失败。 从编写的内容来看,该代码不处理任何异常。 任何未经处理的异常都会导致程序终止。

但该形式是很好的,因为它确保了可调试性。 在罕见情况下,可能需要使用 try/catch,并处理某些异常。 但这应该很罕见,因为正如本主题所述,我们反对将异常作为一种流控制机制用于预期的条件。

记住,让未经处理的异常逃脱无包装的 noexcept 上下文是很糟糕的做法。 在该条件下,C++ 运行时会 std::terminate 进程,因此会失去任何存放的由 C++/WinRT 仔细记录的异常信息。

断言

对应用程序中的内部假设,存在断言。 最好尽可能地为编译时验证使用“static_assert”。 对于运行时条件,请使用带布尔值表达式的 WINRT_ASSERT WINRT_ASSERT 是宏定义,并且扩展到 _ASSERTE。

WINRT_ASSERT(pos < size());

WINRT_ASSERT 在发布版本中编译;在调试版本中,它停止断言所在的代码行上调试程序中的应用程序。

不应在析构函数中使用异常。 因此,至少在调试版本中,你可以断言从带有 WINRT_VERIFY(带有布尔值表达式)和 WINRT_VERIFY_(带有预期结果和布尔值表达式)的析构函数调用函数的结果。

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

相关文章:

使用 C++/WinRT 的错误处理

本主题讨论了处理使用 C/WinRT 编程时出现的错误的策略。 更多常规信息和背景&#xff0c;请参阅错误和异常处理 (Modern C)。 避免捕获和抛出异常 建议继续编写异常安全代码&#xff0c;但最好尽量避免捕获和抛出异常。 如果没有异常处理程序&#xff0c;Windows 将自动生成错…...

计算机基础专升本笔记九-Windows7基础(一)Windows 7 介绍

计算机基础专升本笔记九-Windows7基础 一、Windows简介 Microsoft公司从1983年开始研制Windows系统&#xff0c;最初的研制目标是在MS-DOS的基础上提供一个多任务的图形用户界面。   1985年&#xff0c;第一个版本的Windows 1.0问世&#xff0c;它是一个具有图形用户界面的系…...

LeetCode1109. Corporate Flight Bookings

文章目录 一、题目二、题解 一、题目 There are n flights that are labeled from 1 to n. You are given an array of flight bookings bookings, where bookings[i] [firsti, lasti, seatsi] represents a booking for flights firsti through lasti (inclusive) with sea…...

视觉SLAM十四讲|【五】相机与IMU时间戳同步

视觉SLAM十四讲|【五】相机与IMU时间戳同步 相机成像方程 Z [ u v 1 ] [ f x 0 c x 0 f y c y 0 0 1 ] [ X Y Z ] K P Z \begin{bmatrix} u \\ v \\ 1 \end{bmatrix} \begin{bmatrix} f_x & 0 & c_x \\ 0 & f_y & c_y \\ 0 & 0 & 1 \end{bmatrix} \…...

js null和undefined的区别

null和undefined在JavaScript中都表示“无”的概念&#xff0c;但它们在使用和含义上有一些重要的区别。 含义&#xff1a; null 是一个表示“无”的对象&#xff0c;当转换为数值时结果为0。 undefined 是一个表示“缺少值”的原始值&#xff0c;当转换为数值时结果为NaN。…...

Arduino| IDE下载、安装和设置以及开发板的连接

IDE下载、安装和设置以及开发板的连接 IDE下载IDE安装IDE设置首选项——设置语言、字体、主题、地址等等开发板管理器——添加开发板 开发板的连接 IDE下载 第一步&#xff1a;进入Arduino官网https://www.arduino.cc。 第二步&#xff1a;选择导航栏的Software&#xff0c;然…...

Linux之Ubuntu环境Jenkins部署前端项目

今天分享Ubuntu环境Jenkins部署前端vue项目 一、插件安装 1、前端项目依赖nodejs&#xff0c;需要安装相关插件 点击插件管理&#xff0c;输入node模糊查询 选择NodeJS安装 安装成功 2、配置nodejs 点击后进入 点击新增 NodeJS 配置脚手架类型&#xff1a;如果不填 默认npm …...

QT下的几种实现modbus的库,记录

QModbus QT提供了一个名为QModbus的模块,可以实现Modbus的主机或从机功能 pro需要添加 QT += serialbus serialport相关头文件 #include <QModbusTcpClient> #include <QModbusDataUnit> 具体使用参考: https://blog.csdn.net/XCJandLL/article/details/1…...

HarmonyOS4.0系统性深入开发18公共事件简介

公共事件简介 HarmonyOS通过CES&#xff08;Common Event Service&#xff0c;公共事件服务&#xff09;为应用程序提供订阅、发布、退订公共事件的能力。 公共事件从系统角度可分为&#xff1a;系统公共事件和自定义公共事件。 系统公共事件&#xff1a;CES内部定义的公共事…...

华为路由器OSPF动态链路路由协议配置

R1配置 interface GigabitEthernet0/0/0ip address 10.1.12.1 255.255.255.252 interface LoopBack0ip address 1.1.1.1 255.255.255.255 ospf 1 router-id 1.1.1.1 area 0.0.0.0 network 1.1.1.1 0.0.0.0 network 10.1.12.0 0.0.0.3 R2配置 interface GigabitEthernet0/0/0i…...

常用注解/代码解释(仅个人使用)

目录 第一章、代码解释①trim() 方法以及(Arrays.asList(str.split(reg)));②查询字典项②构建后端镜像shell命令解释 第二章、注解解释①PropertySource注解与Configurationproperties注解的区别 第三章、小知识①Linux系统中使用$符号表示变量 友情提醒: 先看文章目录&#…...

2024阿里云服务器ECS介绍_全方位解析_CPU性能详解

阿里云服务器ECS英文全程Elastic Compute Service&#xff0c;云服务器ECS是一种安全可靠、弹性可伸缩的云计算服务&#xff0c;阿里云提供多种云服务器ECS实例规格&#xff0c;如经济型e实例、通用算力型u1、ECS计算型c7、通用型g7、GPU实例等&#xff0c;阿里云百科aliyunbai…...

向伟人学习反焦虑,在逆境中崛起

第一、乐观的精神。 伟人在长期以来的读书、思考和实践&#xff0c;突破了思想认知限制&#xff0c;并最终在更高的思维层面上&#xff0c;建立起了强大的精神信念感。 在危险环境中表示绝望的人&#xff0c; 在黑暗中看不见光明的人&#xff0c; 只是懦夫与机会主义者。 —— …...

线上问题整理

JVM 案例 案例一&#xff1a;服务器内存不足&#xff0c;影响Java应用 问题&#xff1a; 收到报警&#xff0c;某Java应用集群中一台服务器可用内存不足&#xff0c;超过报警阈值。 排查过程&#xff1a; 首先&#xff0c;通过Hickwall查看该应用各项指标&#xff0c;发现无论…...

【elastic search】详解elastic search集群

目录 1.与集群有关的一些概念 2.集群搭建 3.集群搭建 4.kibana链接集群 5.选举流程 6.请求流程 7.master的作用 1.与集群有关的一些概念 数据分片&#xff1a; 数据分片&#xff08;shard&#xff09;&#xff0c;单台服务器的存储容量是有限的&#xff0c;把一份数据…...

近红外光谱分析技术与基于深度学习的化学计量学方法

郁磊【副教授】&#xff1a;主要从事AI人工智能与大数据分析等相关研究&#xff0c;长期致力于人工智能与近红外生物医学工程等领域融合&#xff0c;主持并完成多项科研课题。著有《神经网络43个案例分析》等书籍。 // 讲座内容 1、近红外光谱基本理论、近红外光谱仪基本原理…...

Elasticsearch windows开箱即用【记录】

一、准备工作 安装ES之前要在本机安装好JDK&#xff0c;对应的兼容性见官网链接&#xff1a;https://www.elastic.co/cn/support/matrix ES官网链接&#xff1a;https://www.elastic.co/cn/, 我本机安装的是JDK8&#xff0c;测试使用的是7.3.0版本的ES和Kibana。 1、首先去…...

第 3 课 ROS 常用术语及命令说明

1.ROS文件系统的组成 ROS 文件是由 Packages 和 Manifests &#xff08; package.xml &#xff09;组成。 Packages&#xff1a;功能包&#xff0c;是 ROS 软件中的基本单元&#xff0c;包含节点源码、配置文件、数据定义等。 Manifest&#xff08; package xml &#x…...

基于AidLux的智慧教育版面分析应用

基于AidLux的智慧教育版面分析应用 1. Aidlux平台介绍 融合架构操作系统AidLux,可以为单一ARM设备同时提供Android和Linux运行环境&#xff0c;双系统既能独立使用又能相互通信。 非虚拟机方式实现双系统融合并行 同时拥有两个系统的完整用户体验无需重启即可在两个系统之间…...

Spring | Spring框架最基本核心的jar包、Spring的入门程序、依赖注入

目录&#xff1a; 1.Spring框架最基本、最核心的jar包2.Spring的入门程序3.依赖注入3.1 依赖注入的概念3.2 依赖注入的实现方式 1.Spring框架最基本、最核心的jar包 Spring是一个轻量级框架&#xff0c;Spring最基本、最核心的的jar包括 : beans、context、core、expression。 …...

[晓理紫]每日论文推送(有中文摘要,源码或项目地址)--大模型相关、扩散模型、视觉导航

专属领域论文订阅 VX关注{晓理紫|小李子}&#xff0c;每日更新论文&#xff0c;如感兴趣&#xff0c;请转发给有需要的同学&#xff0c;谢谢支持 分类: 大语言模型LLM视觉模型VLM扩散模型视觉导航具身智能&#xff0c;机器人强化学习开放词汇&#xff0c;检测分割 LLM 标题:…...

【软件项目管理_软件工程】软件项目管理课后相关习题

(1)需求分析是回答系统必须&#xff08;A&#xff09;的问题。 A.做什么 B.怎么做 C.何时做 D.为谁做(2)WBS非常重要&#xff0c;下列哪项不是其很重要的原因&#xff08;D&#xff09;。 A.帮助组织工作 B.防止遗漏工作 C.为项目估算提供…...

Docker-Compose:教你入门到精通

引言 在当今的软件开发和运维领域&#xff0c;容器技术已经成为了一种非常重要的技术。而Docker-Compose作为Docker的重要工具之一&#xff0c;可以帮助我们轻松地管理和运行容器化的应用程序。本文将详细介绍Docker-Compose的入门到精通知识&#xff0c;帮助你更好地掌握这项技…...

软件设计不是CRUD(10):低耦合模块设计理论——业务抽象:从需求中提取业务维度

接上文《软件设计不是CRUD(9):低耦合模块设计理论——设计落地所面临的挑战》 2、什么是业务抽象 业务抽象是一种将需求落地成模块功能的设计思想,是对业务需求和技术设计进行转换、隔离的一种分析方法。经过业务抽象后的业务模块一般具有较高的业务屈服度,能更大程度满…...

S1-08 流和消息缓冲区

流缓冲区 流缓冲区一般用在不同设备或者不同进程间的通讯&#xff0c;为了提高数据处理效率和性能&#xff0c;设置的一定大小的缓冲区&#xff0c;流缓冲区可以用来存储程序中需要处理的数据、对象、报文等信息&#xff0c;使程序对可以对这些信息进行预处理、排序、过滤、拆…...

Java重修第五天—面向对象3

通过学习本篇文章可以掌握如下知识 1、多态&#xff1b; 2、抽象类&#xff1b; 3、接口。 之前已经学过了继承&#xff0c;static等基础知识&#xff0c;这篇文章我们就开始深入了解面向对象多态、抽象类和接口的学习。 多态 多态是在继承/实现情况下的一种现象&#xf…...

【征稿进行时|见刊、检索快速稳定】2024年经济发展与旅游管理国际学术会议(ICEDTM 2024)

【征稿进行时|见刊、检索快速稳定】2024年经济发展与旅游管理国际学术会议(ICEDTM 2024) 2024 International Conference Economic Development and Tourism Management(ICEDTM 2024) 一、【会议简介】 ICEDTM 2024将围绕"旅游管理”“经济发展”的最新研究领域&#xff…...

瑞_Java开发手册_(四)安全规约

&#x1f64a;前言&#xff1a;本文章为瑞_系列专栏之《Java开发手册》的安全规约篇。由于博主是从阿里的《Java开发手册》学习到Java的编程规约&#xff0c;所以本系列专栏主要以这本书进行讲解和拓展&#xff0c;有需要的小伙伴可以点击链接下载。本文仅供大家交流、学习及研…...

Docker 安全必知:最佳实践、漏洞管理与监控策略

容器安全是实施和管理像 Docker 这样的容器技术的关键方面。它包括一组实践、工具和技术&#xff0c;旨在保护容器化应用程序及其运行的基础架构。在本节中&#xff0c;我们将讨论一些关键的容器安全考虑因素、最佳实践和建议。 容器隔离 隔离对于确保容器化环境的强大性和安全…...

【Flutter】多线程

Flutter 作为一个跨平台的UI库&#xff0c;前面的Flutter 架构有涉及到&#xff0c;Flutter 架构中的运行的多个线程。那么最为一个Flutter开发者&#xff0c;我们如何创建线程呢 多线程 上述我们提及到了&#xff0c;架构层涉及的多线程问题。比如说 主线程, 平台线程&#x…...