-1

一些资源正在描述“异常处理”主题,例如 Wikipedia 和更多资源。但他们中很少有人解释异常本身是什么。也许他们认为这很明显。我可以在Oracle 文档中找到一个很好的简短解释:

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

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

编辑:

  • 我需要一个异常的例子。例如在 C++ 中。
  • 我需要知道它与错误有什么区别?
4

3 回答 3

4

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

从技术上讲,异常被表示为一个简单的对象。异常对象有点特殊,因为它们可以从执行的内部级别“抛出”到“捕获”它们的外部级别,通常在抛出者和捕获者之间的所有级别中放弃代码。

C++、Java 和 C# 是许多具有异常处理机制形式的语言的几个例子。严格来说,C 没有异常的概念(至少是开箱即用的)。

于 2013-06-30T14:06:26.123 回答
2

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

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

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

因此,另一种处理方式是抛出异常。效果是函数结束,但不返回任何值。现在,很明显,调用函数有问题,因为事情的正常流程被打乱了:函数调用没有返回值。接下来可能发生的事情有两种可能性:调用函数已经为此做好了准备,方法是将调用放在ftry-catch 子句中:

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-clause,则再次抛出异常,即调用函数突然结束,并停止调用者的调用者以检查是否有一些异常的catch-code。如果没有,它也结束并且调用函数的函数停止,依此类推,直到到达调用堆栈的顶部(即 的级别main)并且如果那里仍然没有 catch 子句,则整个程序终止并操作系统被告知进程的中止。

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

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

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

但与bug不同的是,编写函数的程序员预见到了问题的可能性,并准备了适当的 throw 和 catch 代码来处理它,方法是让程序以受控的方式关闭,或者以其他方式对问题做出适当的反应。

关于您问题的核心:异常本身是什么?异常是“抛出异常”时创建的对象。您可以将其视为对返回值的某种替代,因为异常对象实际上以与返回值类似的方式传递给调用者。但与实际返回值不同的是,调用者被告知发生的事情是一个异常,它必须按照我上面描述的方式处理它。此外,数据类型异常的不是声明为函数返回类型的数据类型。事实上,它可以(几乎)是任何数据类型。特别是,它可以是一个复杂的对象,其成员变量使用描述异常情况的值进行初始化。一个典型的异常对象是 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 子句中并添加 catch 子句来捕获此类异常:fmy_exception

try
{
  f();
} catch (const my_exception &e) {
   std::cerr << "A problem has occurred when evaluating f(): "
             << e.what()
             << std::endl;
}

在这个例子中,我们使用异常对象的what()函数来打印问题的描述。在 catch 子句完成后,调用者将照常继续。(如果不希望这样做,throw;可以在 catch 子句中使用以重新抛出异常,以便将其传递给调用者的调用者,依此类推。)

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

于 2013-06-30T14:39:57.713 回答
0

异常是您在执行某些事情时抛出的对象,如果出现任何问题。

就像当您“尝试”执行该方法时一样,您可以“捕获”任何错误而不会使程序崩溃。

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

然后每当你想打电话doSmth()

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

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

于 2013-06-30T14:15:22.637 回答