C++ std::bad_可选_访问是针对异常的小型犯罪吗?
如果在C++ std::bad_可选_访问是针对异常的小型犯罪吗?,c++,exception,std,optional,hierarchy,C++,Exception,Std,Optional,Hierarchy,如果在optional没有初始化实际值时调用std::optional的value()成员函数,则抛出std::bad\u optional\u访问。由于它直接从std::exception派生,因此需要catch(std::bad_可选的\u访问常量&)或catch(std::exception const&)来处理异常。然而,这两种选择对我来说似乎都是悲哀的: std::exception捕获每个异常 std::bad_可选_访问公开实现细节。考虑下面的例子: 因此,要捕获异常,您需要充
optional
没有初始化实际值时调用std::optional
的value()
成员函数,则抛出std::bad\u optional\u访问。由于它直接从std::exception
派生,因此需要catch(std::bad_可选的\u访问常量&)
或catch(std::exception const&)
来处理异常。然而,这两种选择对我来说似乎都是悲哀的:
std::exception
捕获每个异常
std::bad_可选_访问
公开实现细节。考虑下面的例子:
因此,要捕获异常,您需要充分了解项
的实现中std::optional
的用法,并将其引导到已知问题的列表中。我不想捕获并重写std::bad_optional_access
,因为(对我来说)异常的关键部分是在需要时忽略它们的可能性。这就是我对正确方法的看法:
std::exception
<- std::logic_error
<- std::wrong_state (doesn't really exist)
<- std::bad_optional_access (isn't really here)
最后,
- 为什么
std::bad_可选_访问
设计成这样
- 我感觉异常正确吗?我的意思是,它们是为这种用途而引入的吗
注意:boost::bad_可选_访问
源自std::logic_error
。很好
注2:我知道catch(…)
和抛出类型不同于std::exception
家族的对象。为了简洁(和理智),省略了它们
更新:不幸的是,我不能接受两个答案,所以:如果你对这个话题感兴趣,你可以阅读胡祖甸的答案和他们的评论 首先,如果您不想公开该实现,那么异常甚至不应该跨越实现和客户机代码之间的边界。这是一个常见的习惯用法,任何异常都不应跨越库、API等的边界
接下来,将某些内容存储在可选的中是您应该自己控制的实现。这意味着您应该检查可选项是否为空(至少如果您不希望客户端知道实现的详细信息)
最后,回答以下问题:客户机代码对空对象执行操作是错误吗?如果允许这样做,则不应抛出任何异常(例如,可能返回错误代码)。如果这是一个不应该发生的实际问题,那么抛出异常是合适的。您可以捕获代码中的std::bad_optional_access
,并从catch
块抛出其他内容。如果您不想公开该实现,那么异常甚至不应该跨越实现和客户机代码之间的边界。这是一个常见的习惯用法,任何异常都不应跨越库、API等的边界
接下来,将某些内容存储在可选的中是您应该自己控制的实现。这意味着您应该检查可选项是否为空(至少如果您不希望客户端知道实现的详细信息)
最后,回答以下问题:客户机代码对空对象执行操作是错误吗?如果允许这样做,则不应抛出任何异常(例如,可能返回错误代码)。如果这是一个不应该发生的实际问题,那么抛出异常是合适的。您可以捕获代码中的std::bad_optional_access
,并从catch
块抛出其他内容
因此,要捕获异常,您需要充分了解std::optional
在项目实现中的用法
不,要捕获异常,您必须阅读get\u placement
的文档,该文档将告诉您它抛出std::bad\u可选访问权。通过选择发出该异常,函数将该异常的发出作为该函数接口的一部分
因此,与直接返回一个std::optional
时相比,它不再依赖于项的实现。您选择将其放在界面中,因此您应该承担后果
换句话说,如果您觉得将std::optional
作为参数类型或返回值是错误的,那么直接发出bad\u optional\u异常
也应该有同样的感觉
归根结底,这一切都可以追溯到错误处理的一个最基本问题:在错误的具体性质变得毫无意义甚至完全不同之前,你能离错误发生地有多远
假设您正在进行文本处理。有一个文件,每行包含3个浮点数。您正在逐行处理它,并将每组三个值插入到一个列表中。还有一个函数将字符串转换为浮点数,如果转换失败,它将抛出一个异常
因此,代码大致如下所示:
try {
unit.equip_item(item);
} catch (std::wrong_state const& exception) { // no implementation details
inform_client(exception.what());
}
for each line
split the line into a 3-element list of number strings.
for each number string
convert the string into a number.
add the number to the current element.
push the element into the list.
好吧,那么。。。如果字符串到浮点转换器抛出,会发生什么情况?视情况而定;你想发生什么?这取决于谁抓住了它。如果需要错误的默认值,则最内层循环中的代码将捕获该错误并将默认值写入元素
但您可能希望记录某一行有错误,然后跳过该行(不要将其添加到列表中),但继续正常处理其余文本。在这种情况下,您将在第一个循环中捕获异常
此时,错误的含义已经改变。抛出的错误是“此字符串不包含有效的浮点”,但代码不是这样处理的。事实上,捕获代码完全丢失了错误的上下文。它不知道是什么时候
try {
unit.equip_item(item);
} catch (std::wrong_state const& exception) { // no implementation details
inform_client(exception.what());
}
for each line
split the line into a 3-element list of number strings.
for each number string
convert the string into a number.
add the number to the current element.
push the element into the list.