什么是例外?

时间:2013-06-30 13:55:41

标签: c++ exception

有几个资源正在描述像“维基百科”这样的“异常处理”主题以及更多的资源。但很少有人解释说什么是例外本身。也许他们认为它非常明显。我可以在Oracle documentation找到一个很好的简短说明:

  

定义:异常是在执行a期间发生的事件   程序,会破坏程序指令的正常流程。

本文的其余部分是关于Java编程的异常。但我不太了解Java以阅读整个文档。我需要澄清例外情况。

编辑:

  • 我需要一个例外的例子。例如在C ++中。
  • 我需要知道bug有什么区别?

3 个答案:

答案 0 :(得分:4)

从概念上讲,异常是一种不应该在程序的正常运行中发生的情况。例如,远程服务器不可用,输入格式不正确,文件未找到,系统内存不足......根据类型和情况,程序可能有也可能无法进行处理它。

从技术上讲,异常表示为简单对象。异常对象在某种意义上是特殊的,它们可以从内部执行级别“抛出”到“捕获”它们的外部级别,通常会抛弃thrower和catcher之间所有级别的代码。

C ++,Java和C#是许多具有异常处理机制形式的语言的一些示例。严格地说,C没有例外的概念(开箱即用,至少)。

答案 1 :(得分:2)

"抛出异常" (有时也被称为"引发异常")是一种结束函数的方法,当由于某种原因,函数无法完成预期完成的任务时。

示例:您有一个函数f,它接受​​float参数,并且应该计算并返回其自然对数。现在,在计算过程中的某个时刻,事实证明它传递的参数是0。无法计算0的对数,那么该函数应该做什么?

处理这种情况的一种方法是返回一个特殊值(例如NaN,非{数字值float),但这可能会误导函数的调用者:函数在某个变量上调用,并返回一些值。一切看起来都很正常,而实际上没有什么是正常的 - 功能无法完成它的工作。

因此,另一种处理方法是抛出异常。结果是函数结束,但不返回任何值。现在,显然,调用函数存在问题,因为事物的正常流动受到干扰:函数调用没有返回任何值。接下来可能发生的事情有两种可能性:通过在{try-catch子句中调用f调用函数来为此做好准备:

try {
  log_of_val = f(val);
} catch (const exception &e) {
   /* Description of what to do when
      an exception is thrown by f. */
}

如果f引发的异常与其中一个catch子句中定义的异常类型匹配,则执行第一个这样的catch子句。

如果没有这样的catch子句,则再次抛出异常,即调用函数突然结束,调用者的调用者停止检查是否有一些catch代码例外。如果没有,它也结束并且函数调用函数被停止,依此类推,直到达到调用堆栈的顶部(即main的级别)并且如果那里仍然没有catch子句,则整个程序终止,并通知操作系统流程的中止。

因此,如果没有适当的catch子句,异常就有能力降低整个过程。但是比例简单地调用类似exit(1)之类的例外更好,因为它不会立即终止进程。它首先让调用者有机会对问题作出反应,然后是调用者的调用者,依此类推。

异常抛出机制还确保在当前函数结束之前正确地破坏和解除分配局部变量。因此,就智能指针等管理的自动变量和动态内存而言,您不会遇到内存泄漏和类似问题。

总而言之,异常(以及整个抛出和捕获机制)是一种处理异常的方法,但可能并且在某种程度上预期< / em>程序流程中的事件。通常,它可以在函数调用中发生的事件使得函数的正确执行变得不可能,但是不能在函数内阻止这种事件。如果调用函数传递不合适的参数,或者为程序提供不合适的输入的用户,这些事件通常是调用函数的责任。此外,与系统状态相关的问题,例如内存不足,往往会通过抛出异常来处理。

但与 bugs 不同,编写函数的程序员预测了问题的可能性,并使用合适的throw和catch代码来准备代码,以便通过以受控方式关闭程序来处理它,或以其他方式适当地对问题做出反应。

关于你问题的核心:什么是异常本身?异常是在抛出&#34;异常时创建的对象&#34;。您可以将其视为返回值的某种替换,因为异常对象实际上以与返回值类似的方式传递给调用者。但与实际返回值不同,调用者被告知发生了什么是一个例外,它必须按照我上面描述的方式处理这个问题。此外,异常的数据类型不是声明为函数返回类型的数据类型。实际上,它可以(几乎)任何数据类型。特别是,它可以是一个复杂的对象,其成员变量使用描述异常情况的值进行初始化。典型的异常对象是C ++属于类类型,通常(但不一定)定义为类似这样的东西:

#include <exception>

class my_exception : public std::exception
{
public:
  explicit my_exception(const char *description)
    : std::exception() , description_(description)
  { }

  virtual const char *what() const noexcept
  { return description_; }

private:
  const char *description_;
};

因此,它是在字符串上构造的用户定义对象,在内部存储指向字符串的指针,并提供返回字符串的成员函数what()。我们的想法是,在抛出异常时定义字符串,并且它包含对问题的一些描述。

f的调用者可以通过在try-clause中包含对f的调用并为{{1}添加catch子句来捕获此类异常}}:

my_exception

在此示例中,我们使用异常对象的try { f(); } catch (const my_exception &e) { std::cerr << "A problem has occurred when evaluating f(): " << e.what() << std::endl; } 函数来打印问题的描述。 catch-clause完成后,调用者将继续正常运行。 (如果不需要,可以在catch子句中使用what()来重新抛出异常,以便将其传递给调用者的调用者,依此类推。)

再次注意,异常可以是用户定义的对象, 可以从throw;派生,而可以 em>覆盖std::exception函数以将问题描述作为字符串返回,但这些都不是必需的。您也可以抛出字符串本身,或者what()作为例外。

答案 2 :(得分:0)

异常是一个在执行某些事情时抛出的对象,如果出现任何错误。

就像当你“试着”执行这个方法一样,你可以“抓住”任何错误而不会导致你的程序崩溃。

void doSmth()
{
.
.
.
  if(somthingWentWorng)
    throw Exception("Not Good!")
.
.
.
}

然后,只要您想致电doSmth()

try
{
  doSmth();
}
catch (Exception &e)
{
  cout << e.what() << endl;
}

这样,如果在执行doSmth时出现问题,您可以在没有应用程序崩溃的情况下解决问题。