[英]How to handle runtime errors in C++?
所以,我对 C++ 有点陌生,我想知道什么是好的做法,甚至在编程时如何处理运行时错误,这里有一个例子:
State s_toState(std::string state){
if (state == "MG")
return State::MG;
else if (state == "PR")
return State::PR;
else if (state == "SP")
return State::SP;
else if (state == "SC")
return State::SC;
else if (state == "RJ")
return State::RJ;
else if (state == "RN")
return State::RN;
else if (state == "RS")
return State::RS;
// ???
}
所以我有这个 function 将string
转换为State
。 在不使用异常的情况下,我断言给定的 state 是现有的(MG、PR、SP 等)的理想方法是什么?
举个例子,但我要求的是一般规则。 据我所知,我可以使用异常、断言或只打印错误。 我也假装对此进行单元测试(也是单元测试的新手,对此一无所知)。
这看起来是一个使用异常的好机会。 cplusplus.com 指南是合理的,但我发现玩弄它是一种更好的学习方式。
基本思想是这样的:
throw
异常,终止 function 并将异常传递给调用 function 的任何人。try
块中调用了 function,那么接下来的catch
就会被执行。try
/ catch
系统,则调用者也会被终止,并且该过程会重复 function 调用堆栈,直到找到try
/ catch
或main()
终止。 答案取决于s_toState
“承诺”要做什么。
如果state
无效是 function 或其他内部逻辑错误的程序员的错误。 添加assert
并记录 state 有效性作为前提条件(与指针的!=nullptr
相同)。 对于发布版本,添加一些默认行为,这样程序就不会在可能的情况下崩溃。 或者如果你不写关键的软件就让它崩溃,它至少会使调试更容易。
如果它是用户的可恢复错误和合理的场景(不是错误),则考虑返回std::optional
或throw
。 当抛出的异常总是被直接调用者捕获时,我更喜欢前者,即从不向上传播调用堆栈。 我也发现它更清楚,因为它强制调用者明确处理它。
对于不可恢复的错误,即当直接调用者无法处理nullopt
时,只需抛出并让其他代码处理即可。
我喜欢try_parse
返回std::optional
的命名约定,同时parse
抛出。
尝试一下异常和错误处理常见问题解答可能是值得的。
一般来说,处理此类错误(如任何错误)的方式取决于整个程序的需求 - 而您尚未指定。 所以没有一刀切的“一般规则”。
有选择和权衡。
一种选择是为您的State
枚举类型提供表示未确定或无效 state 的枚举器值,例如
enum class State {MG, PR, Undetermined};
然后,在您的 function 中,返回未确定的值,例如
State s_toState(const std::string &state)
{
State return_value = State::Undetermined;
if (state == "MG")
return_value = State::MG;
else if (state == "PR")
return_value = State::PR;
// etc
return return_value;
}
使用这种方法, function 始终返回State
类型的有效值。 如果错误条件不是很严重(即如果提供了无效字符串,程序可以继续),那么调用者可以决定是否需要检查返回值。 可以报告多种类型的错误条件(例如,通过具有表示不同错误的多个枚举值)不利的一面是调用者可能忘记检查返回值并且行为不正确。
另一种选择是抛出异常,例如;
State s_toState(const std::string &state)
{
if (state == "MG")
return State::MG;
else if (state == "PR")
return State::PR;
// etc
throw std::invalid_argument("Bad input string");
}
这个选项需要对抛出什么类型的异常做出明智的选择(例如,需要传达关于错误状态的什么信息)。 如果提供了错误的字符串,调用者(或整个程序)无法合理地继续,则此方法可能更可取,因为通过抛出异常,调用者被迫捕获并采取任何恢复操作以避免被终止。 因此,这种方法可能不适用于非关键错误——例如,如果提供了错误的字符串,则可以合理地继续执行。
另一种选择(C++17 及更高版本)是返回std::optional<State>
。 这允许调用者检查是否发生了错误(例如std::option::has_value()
return false
),或者,如果在没有检查的情况下访问该值,则导致抛出std::bad_optional_access
类型的异常(其中可能适合呼叫者,或者可能不提供信息)。
也可以使用assert()
- 如果指定的条件不正确,它会强制终止。 通常,我更喜欢使用assert()
抛出异常,但您可能更喜欢其他方式。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.