繁体   English   中英

如何处理 C++ 中的运行时错误?

[英]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 指南是合理的,但我发现玩弄它是一种更好的学习方式。

基本思想是这样的:

  • function throw异常,终止 function 并将异常传递给调用 function 的任何人。
  • 如果调用者在try块中调用了 function,那么接下来的catch就会被执行。
  • 如果调用者没有try / catch系统,则调用者也会被终止,并且该过程会重复 function 调用堆栈,直到找到try / catchmain()终止。

答案取决于s_toState “承诺”要做什么。

如果state无效是 function 或其他内部逻辑错误的程序员的错误。 添加assert并记录 state 有效性作为前提条件(与指针的!=nullptr相同)。 对于发布版本,添加一些默认行为,这样程序就不会在可能的情况下崩溃。 或者如果你不写关键的软件就让它崩溃,它至少会使调试更容易。

如果它是用户的可恢复错误和合理的场景(不是错误),则考虑返回std::optionalthrow 当抛出的异常总是被直接调用者捕获时,我更喜欢前者,即从不向上传播调用堆栈。 我也发现它更清楚,因为它强制调用者明确处理它。

对于不可恢复的错误,即当直接调用者无法处理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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM