回答您的问题取决于所涉及的编程语言。
C并没有异常处理机制,尽管有一些专有语言扩展。
C++ 提供了在代码中的任意位置“抛出”任意对象并在调用堆栈的更高层次上“捕获”它的方式。
C#提供了“抛出”派生自System.Exception
的对象以及从堆栈较高处“捕获”这些异常的方式。此外,我认为.NET运行时会报告由于抛出异常本身而引发的一些问题。
- 什么是异常?它在内存中的最低级构成是什么?在.NET中,我可以将其视为某些异常类型的某个对象实例。在原生世界中,它由什么构成?一些数据结构吗?
在C++中,它只是一个像其他对象一样在代码中创建的任意对象:
throw 42; // throws an int object
throw "blah"; // throws a char[5] object
throw std::string("arg!"); // throws a std::string object
throw my_type(42); // throws a my_type object
throw std::exception("doh!"); // throws a std::exception object
抛出的异常与catch
语句的匹配方式与重载函数的匹配方式非常相似。(一个很大的区别是catch语句是有序的。也就是说,第一个能匹配的catch语句将“获胜”并捕获对象。然而,重载函数必须始终提供明确的最佳匹配。)
在C++中,异常几乎只能从代码中抛出。它可能是您自己的代码、其他人的代码、某个库的代码或标准库的代码。但通常会在某个地方有一个 throw
语句。也有一些例外情况(不是故意的),比如由new
引发的std::bad_alloc
(它可能是从代码中的throw
语句引发的,但我认为不一定需要),以及从 dynamic_cast<>
引发的std::bad_cast
。(此外,下一个标准,C++1x,预计在明年发布,允许异常以某种方式跨越线程边界,这可能需要标准库实现者找到一种方法来在一个线程中存储异常并从另一个线程中重新引发它。但我对此还不太熟悉。)
如果异常在程序员的代码中没有被显式地抛出,那么是谁创建了这个异常?它是某些语言运行时提供的支持的一部分吗?
SomeException e = new SomeException()
在C++中,你
可以抛出
指针,但你很少这样做。通常情况下,你会使用
throw
关键字来抛出异常对象而不是指针。
In C++, throwing pointers can lead to memory leaks and undefined behavior if not properly handled.
SomeException e
或者
throw SomeException();
- 异常工作范式是什么?当发生错误时,语言运行时是否创建相应数据结构/类型的实例来表示错误详情?
除了C++标准库会抛出异常之外,我只能想到上面提到的两个特性(还有C++1x中的一个),即“运行时”(runtime)抛出异常时。
- 如何知道所有可能在运行时产生的意外情况,并因此创建足够的异常数据结构/类型来代表它们?
在C++中,通常只抛出从std::exception
派生的类对象,尽管我曾遇到过使用自己的异常类层次结构的代码,这些类没有根源于std::exception
。标准库中异常层次结构的问题在于其类互相非虚拟继承,这使得不可能使用多重继承将自己的异常层次结构遮盖住标准库中的异常层次结构。(比如具有自己的OutOfRange
异常类型,其从std::out_of_range
和从您的异常基类MyException
继承,MyException
又从std::exception
继承。)
C++处理异常的方法主要基于以下原则:
- 以使其免于在任何点抛出异常的方式编写您的代码。使用RAII和其他技术来实现这一点。
- 仅在可以对它们做出响应的位置捕获异常。
- 只在非常规情况下抛出异常。不要将其用于控制流程。(C ++异常的设计目标是为了使供应商能够实现它们,从而在非异常情况下最小化开销,而以成本换取异常情况。)