C++异常处理面试题

17 Mar 2025 | 6 分钟阅读

在开始问答之前,我们先简要介绍一下 C++ 中的异常和异常处理。

Top C++ Exception Handling Interview Questions

异常是任何不符合预期的事件。它是在程序执行过程中发生的异常情况。它表示运行时代码的错误或失败。

异常可能由于各种原因发生,包括:

  • 运行时错误: 这些是在程序运行时发生的错误,例如除以零、访问无效内存位置或尝试执行非法操作。
  • 外部条件: 异常可能由外部因素引起,例如输入/输出错误、网络故障或系统资源不足。
  • 无效数据或输入: 程序在收到意外或无效数据或输入时可能会遇到异常。例如,我试图将非数字字符串解析为数字。
  • 环境条件: 某些环境条件或情况可能导致异常。例如,文件未找到错误、数据库连接失败或硬件故障。

C++ 中的异常处理是一种允许您在运行时处理错误的机制。

异常处理机制由以下要素组成:

  • Try 块: 在 C++ 中,try 块用于包含可能抛出异常的代码。它是异常处理的起点,允许您监视异常并妥善处理它们。
  • Catch 块: 在 C++ 中,catch 块用于捕获和处理在相应 try 块中抛出的异常。当抛出异常时,程序会搜索匹配的 catch 块来处理该特定类型的异常。
  • Throw 表达式: 在 C++ 中,throw 语句用于在程序中手动引发或抛出异常。它允许您指示发生了异常情况。throw 语句通常后面跟着一个表示被抛出异常对象的表达式。该表达式可以是任何类型,包括内置类型、用户定义类型,甚至是标准库异常类。

现在,我们将讨论面试题和答案。

1) C++ 中的异常处理是什么?

异常处理是 C++ 中处理运行时错误的一种机制,或者是在程序执行期间可能发生的异常情况。它允许您快速捕获和处理这些错误。


2) 使用异常处理有什么好处?

异常处理提供了一种将错误处理代码与标准代码分离的方法。它有助于使代码更易于阅读和维护。

  • 它允许错误在程序的各个级别之间传播。
  • 它有助于处理异常情况并快速从错误中恢复代码。
  • 它使得实现集中式错误处理机制的可能性成为可能。

3) C++ 中的异常处理是如何工作的?

在 C++ 中,您可以使用 try、catch 和 throw 关键字来处理异常。

  • 可能抛出异常的代码放在 try 块中。
  • 如果在 try 块中发生异常,则使用 throw 关键字将其抛出。
  • 然后,抛出的异常会被匹配异常类型的相应 catch 块捕获并处理。

4) 编写 throw 语句的重要性?

throw 语句用于在程序中手动引发异常。当特定条件或错误需要立即响应时,通常会使用它。


5) 编写 try 块的重要性?

try 块用于包含可能抛出异常的代码。它允许您监视异常并妥善处理它们。


6) 编写 catch 块的重要性?

catch 块捕获并处理在相应 try 块中抛出的异常。它指定它可以处理的异常类型,并包含在发生指定异常时要执行的代码。


7) 如果抛出一个异常但未被捕获,会发生什么?

如果抛出的异常没有被任何匹配的 catch 块捕获,程序将异常终止。运行时系统将展开调用堆栈,执行任何必要的清理操作,然后终止程序。


8) 可以在 try 块内部嵌套 try 块吗?

是的,您可以在 try 块内部嵌套 try 块。这允许您在程序的执行的不同级别处理异常。如果在内部 try 块中发生异常,程序会在该内部 try 块中搜索匹配的 catch 块,并在需要时继续到外部 try 块。


9) 如何区分已检查异常和未检查异常?

在 C++ 中,与 Java 等其他语言不同,没有直接区分已检查异常和未检查异常。在 C++ 中,如果提供了适当的 catch 块,则可以捕获和处理所有异常。然而,在 Java 等语言中,已检查异常必须在函数签名中声明或在 try-catch 块中捕获,而未检查异常不需要显式处理。


10) 如何区分 throw 和 throws 关键字?

Throw 关键字用于在程序中手动引发异常。而 throws 关键字在某些其他编程语言(如 Java)中使用,用于声明函数或方法可能抛出异常。


11) 在 catch 块中通过值、引用和指针处理异常有什么区别?

按值处理异常涉及复制异常对象。它允许修改异常对象,但会产生复制的开销。

按引用处理异常避免了复制,允许直接访问原始异常对象。

按指针处理异常允许处理 null 指针的可能性,并在重新抛出或重新分配异常对象时提供了灵活性。


12) 析构函数在异常处理中的作用是什么?

析构函数在异常处理中起着至关重要的作用。它们负责清理资源和释放为对象分配的内存。当出现异常时,在 try 块作用域内的对象的析构函数会自动调用。


13) 使用带参数和不带参数的 throw 有什么区别?

当不带参数使用 throw 时,它会在 catch 块中重新抛出当前正在处理的异常。

当带参数使用 throw 时,它会抛出一个指定类型或对象的新异常,该异常可以被适当的 catch 块捕获。


14) 如何在 C++ 中重新抛出异常?

您可以使用不带参数的 throw 语句在 catch 块中重新抛出异常。它会重新抛出当前异常,允许它被外部 catch 块捕获,或者在未被捕获时终止程序。


15) 解释堆栈展开的概念?

堆栈展开是指在抛出异常时,释放调用堆栈中的对象并调用析构函数。运行时在展开堆栈时搜索适当的 catch 块,如果找到匹配的 catch 块,则处理异常。


16) 标准异常和自定义异常有什么区别?

标准异常是 C++ 标准库提供的预定义异常类,例如 std::runtime_error 或 std::invalid_argument。另一方面,自定义异常是继承自 std::exception 或其派生类的用户定义的异常类。标准异常通常代表常见的错误场景,而自定义异常则针对特定的应用程序需求量身定制。


17) 如何在构造函数和析构函数中处理异常?

构造函数中的异常可以通过在构造函数体中使用 try-catch 块来处理。如果在析构函数执行期间发生异常,并且该异常未在析构函数本身中捕获,则程序将终止。


18) 可以按引用而不是按值捕获异常吗?

您可以按引用而不是按值捕获异常。通常建议按引用捕获异常,以避免不必要地复制异常对象。


19) 解释异常安全的概念。

异常安全是指即使在存在异常的情况下,程序也能维护一致状态的保证。它涉及代码的设计,以便适当管理资源,不会发生内存泄漏,并且无论程序执行期间是否发生异常,对象都处于有效状态。


20) 异常安全有哪些不同级别?

异常安全通常分为三个级别:

  • 无异常保证: 具有无异常保证的函数确保在任何情况下都不会抛出异常。
  • 基本异常安全: 具有基本异常安全保证的函数确保对象和资源不会泄漏,并且即使抛出异常,程序也能保持有效。
  • 强异常安全: 具有强异常安全保证的函数确保如果发生异常,程序的状会回滚到函数调用之前的状态,而没有内存泄漏或副作用。