std::bad_Optional_access 是针对异常的小犯罪吗?

2024-03-11

If std::optional's value()成员函数被调用时optional没有初始化实际值,astd::bad_optional_access被抛出。因为它直接源自std::exception,你需要catch (std::bad_optional_access const&) or catch (std::exception const&)用于处理异常。然而,这两种选择对我来说似乎都很悲伤:

  • std::exception捕获每一个异常
  • std::bad_optional_access公开实施细节。考虑以下示例:
Placement Item::get_placement() const {
  // throws if the item cannot be equipped
  return this->placement_optional.value();
}
void Unit::equip_item(Item acquisition) {
  // lets the exception go further if it occurs
  this->body[acquisition.get_placement()] = acquisition;
}
// somewhere far away:
try {
  unit.equip_item(item);
} catch (std::bad_optional_access const& exception) { // what is this??
  inform_client(exception.what());
}

因此,要捕获异常,您需要充分了解std::optional in the Item的实施,导致了一系列已知问题。我也不想抓住并重新包装std::bad_optional_access因为(对我来说)例外的关键部分是在需要之前忽略它们的可能性。这就是我认为正确的方法:

std::exception
  <- std::logic_error
    <- std::wrong_state (doesn't really exist)
      <- std::bad_optional_access (isn't really here)

因此,“遥远”的例子可以写成这样:

try {
  unit.equip_item(item);
} catch (std::wrong_state const& exception) { // no implementation details
  inform_client(exception.what());
}

Finally,

  • Why is std::bad_optional_access设计得像这样吗?
  • 我对异常的感觉正确吗?我的意思是,它们是为了这种用途而引入的吗?

Note: boost::bad_optional_access源自于std::logic_error. Nice!

注2:我知道catch (...)并投掷除以下类型以外的物体std::exception家庭。为了简洁(和理智),它们被省略。

更新:不幸的是,我不能接受两个答案,所以:如果你对这个话题感兴趣,你可以阅读胡作典的回答和他们的评论。


您说异常的主要吸引力在于您可以在调用堆栈的尽可能深处忽略它们。据推测,考虑到您希望避免泄漏实现细节,您不能再让异常传播超出其处理程序无法理解和修复的范围。这似乎与您的理想设计相矛盾:它致力于向用户修复异常,但是bad_optional_access::what完全没有关于刚刚发生的事情的上下文——向用户泄露实现细节。当用户看到的最多只是“无法装备物品:bad_Optional_access”时,您如何期望用户针对装备失败采取有意义的操作?

显然你已经过度简化了,但挑战仍然存在。即使有“更好”的异常层次结构,std::bad_optional_access只是没有足够的上下文,除了非常接近的调用者之外的任何东西都可能知道如何处理它。

您可能想要抛出几种截然不同的情况:

  1. 您希望在没有太多语法开销的情况下中断控制流。例如,您有 25 个不同的选项需要解包,并且您希望在其中任何一个失败时返回一个特殊值。您在 25 个访问周围放置了一个 try-catch 块,为自己节省了 25 个if blocks.
  2. 您已经编写了一个通用库,该库执行了许多可能出错的操作,并且您希望向调用程序报告细粒度错误,以使其有最好的机会以编程方式执行一些智能恢复操作。
  3. 您已经编写了一个执行非常高级任务的大型框架,因此您通常期望操作失败的唯一合理结果是通知用户操作已失败。

当您遇到感觉不正确的异常问题时,通常是因为您正在尝试处理一个与您希望的运行级别不同的错误。希望更改异常层次结构只是试图使该异常符合您的特定用途,这会导致与其他人如何使用它的紧张关系。

显然,C++ 委员会认为bad_optional_access属于第一类,你问为什么它不属于第三类。我认为您应该翻转问题并问自己要捕获异常的目的是什么,而不是尝试忽略异常直到您“需要”对它们执行某些操作。

如果答案确实是“用户”,那么你应该抛出一些不是bad_optional_access相反,它具有高级功能,例如本地化错误消息和足够的数据inform_user能够打开一个带有有意义的标题、主文本、副文本、按钮、图标等的对话框。

如果答案是这是一般游戏引擎错误并且可能在游戏的常规过程中发生,那么您应该抛出一些内容,表明装备该物品失败,而不是存在状态错误。与无法描述的状态错误相比,您更有可能从未能装备物品中恢复,包括如果您需要为用户产生一个漂亮的错误。

如果答案是您可能会尝试连续装备 25 件物品,并且一旦出现问题就想停止,那么您无需进行任何更改bad_optional_access.

另请注意,不同的实现使不同的使用或多或少变得方便。在大多数现代 C++ 实现中,不抛出异常的代码路径没有性能开销,并且huge抛出路径上的开销。这通常会阻碍对第一类错误使用异常。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

std::bad_Optional_access 是针对异常的小犯罪吗? 的相关文章

随机推荐

  • Android 到 PC USB 读/写

    我在 PC 上有一个程序 从 USB 接收字符串输入 旧程序 我有一个 Android 4 X 平板电脑 需要向在 PC 上运行的程序提供 USB 上的字符串输入 当我在 Android 上使用示例代码时 以下代码给出了空的哈希图 PC 在
  • 这个“模式”有名字吗?

    我想知道这个 模式 是否有一个名称 其中方法签名称为 TrySomething 例如int TryParse decimal TryParse etc 我的一位同事经常使用这种命名约定 他们不会返回值或抛出异常 而是调用一个方法TryDoS
  • sql Server:按积分总和排名并按排名排序

    我有一个包含以下字段的游戏桌 ID Name Email Points 1 John email protected cdn cgi l email protection 120 2 Test email protected cdn cgi
  • 哪个更快:x<<1 或 x<<10?

    我不想优化任何东西 我发誓 我只是出于好奇而想问这个问题 我知道在大多数硬件上都有位移位的汇编命令 例如shl shr 这是一个单一命令 但移位多少位 从纳秒角度或从 CPU 角度角度 是否重要 换句话说 以下任一选项在任何 CPU 上都更
  • ghc-pkg 检查黑线鳕警告

    全新安装 haskell 平台后 通过homebrew GHC x64 7 6 3 on OSX 10 9 2当我运行时 我收到以下警告ghc pkg check 见下文 Warning haddock interfaces Users u
  • JAXB 解组未知 XML 内容的子集

    我有一个要求unmarshall未知的子集XML内容 对于该未编组的对象 我需要修改一些内容并将相同的 XML 内容 子集 与原始 XML 重新绑定 输入 XML 示例
  • 如何从 C# 解密 ruby​​ 中的 RijandelManaged?

    static byte keyBytes new byte 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 static byte iv new byte 1
  • 为什么指针变量不显示 100 位数字?

    目标 我对准确性有要求 我需要显示 100 位数字或至少 50 位数字 尝试 1 首先我使用了整数变量 然后它只显示 10 位数字 尝试2 在我朋友的帮助下 我使用指针概念 它成功输入了50到100位数字 但指针变量仅显示10位数字 我写的
  • 在rails中执行AJAX Post而不传递authenticity_token

    所以我记得有一次 当我尝试做一篇 AJAX 帖子时 我必须将 form authenticity token 作为数据之一传递给 Rails 由于某种原因 不这样做会产生某种错误 我会立即注销 有没有办法仍然拥有这个真实性令牌用于表单提交但
  • 如何在 htaccess 中启用阿拉伯语 slug?

    我有一个多语言网站 我正在尝试创建一个友好的 URL 在我的数据库中 我有slug场地 当文章的标题是英文时 slug 会出现在 url 中 并且重定向工作正常 但当标题是阿拉伯语时 会出现 slug 并且重定向显示 未找到对象 page
  • 请解释闭包,或将循环计数器绑定到函数范围

    我见过程序员使用计数器在循环内分配事件侦听器 我相信这是语法 for var i 0 i lt someArray length i someArray i onclick function i Some code using i i 有人
  • Material ui 'new' v5.0.0jectFirst 无法设置特异性

    MUI v5 0 0今天发布了 在我的尖峰分支中 我正在尝试更新到新版本 我正在执行 mui docs 中详细的步骤here https mui com guides migration v4 theme 我在用styled compone
  • 如何自动化 Google 主页自动建议?

    这是我的测试类 包含所有代码行 我认为问题出在 xpath 中 因为它无法找到元素 package practice import java util List import org openqa selenium By import or
  • 错误 E QUERY [thread1] 语法错误:使用和/或使用 find() 的属性 id @(shell) 无效

    我在使用此查询时收到错误 db a find or name aekansh age 21 pretty 作为 E 查询 thread1 语法错误 无效的属性 id shell 1 11 集合 a 将数据存储为 id 10 name aek
  • Firestore PERMISSION_DENIED

    当我在 macOS 上编写 flutter 应用程序时遇到这个问题 相同的基本代码在我的 Windows 电脑中工作 但在 macOS 中不起作用 正如您在我的日志中看到的 应用程序已连接 但我仍然无法对我的 Firestore 数据库发出
  • iPhone DropBox API:如何加载文件?

    关于 dropBox 集成到 iPhone 应用程序中的一个非常基本的问题 我按照 DropBoxSDK 的设置进行操作 一切正常 我可以登录我的帐户并将其链接 所以我正确地设置了一切 现在我想用它简单地从 dropBox 加载文件并再次保
  • JSF 错误消息和程序卡住。 JSON 解析错误和 primefaces

    我在facelets中有以下形式
  • 使用Java DSL的Camel CXF POJO模式

    我有一个预先存在的 Web 服务 连接 SOAP 如果可能的话 我想在不使用 Swing 框架的情况下进行调用 我遵循接触优先开发 使用 cxf wsdl2java 工具生成我的 java 文件 我希望从 java 对象中提取用户名和密码并
  • 从 C# 创建 COM 索引属性?

    我正在尝试用新的 net dll 来模仿旧的 vb6 dll 模仿必须是完美的 以便调用者不知道他们正在使用新的 dll 不过我有一个好奇心 在 VB6 中 对象库中有以下内容 Property BankList Index As Long
  • std::bad_Optional_access 是针对异常的小犯罪吗?

    If std optional s value 成员函数被调用时optional没有初始化实际值 astd bad optional access被抛出 因为它直接源自std exception 你需要catch std bad optio