Content deleted Content added
No edit summary Tags: Mobile edit Mobile app edit iOS app edit App section source |
m Fix a syntax error |
||
(23 intermediate revisions by 6 users not shown) | |||
Line 56:
<syntaxhighlight lang="Java">
try {
Scanner stdin = new Scanner(System.in);
String line = stdin.nextLine();
Line 70:
System.out.printf("Error: %s\n", e.getMessage());
} finally {
}
</syntaxhighlight>
Line 95:
The second scheme, and the one implemented in many production-quality C++ compilers and 64-bit Microsoft [[Structured Exception Handling|SEH]], is a {{visible anchor|table-driven approach|text=''table-driven'' approach}}. This creates static tables at [[compile time]] and [[link time]] that relate ranges of the [[program counter]] to the program state with respect to exception handling.<ref>{{cite journal | title=Exception handling – Supporting the runtime mechanism | last=Lajoie | first= Josée | journal=C++ Report | volume=6 | issue=3 | date=March–April 1994}}</ref> Then, if an exception is thrown, the runtime system looks up the current instruction ___location in the tables and determines what handlers are in play and what needs to be done. This approach minimizes executive overhead for the case where an exception is not thrown. This happens at the cost of some space, but this space can be allocated into read-only, special-purpose data sections that are not loaded or relocated until an exception is actually thrown.<ref name=cppeh>{{cite journal | title=Optimizing away C++ exception handling | last=Schilling | first=Jonathan L. | journal=[[SIGPLAN Notices]] | volume=33 | issue=8 | date=August 1998 | pages=40–47 | doi=10.1145/286385.286390| s2cid=1522664 | doi-access=free }}</ref> The ___location (in memory) of the code for handling an exception need not be located within (or even near) the region of memory where the rest of the function's code is stored. So if an exception is thrown then a performance hit – roughly comparable to a function call<ref name=MiscrosoftDocsExceptions>{{cite web|title=Modern C++ best practices for exceptions and error handling|work=Microsoft|date=8 March 2021|access-date=21 March 2022|url=https://docs.microsoft.com/en-us/cpp/cpp/errors-and-exception-handling-modern-cpp}}</ref> – may occur if the necessary exception handling code needs to be loaded/cached. However, this scheme has minimal performance cost if no exception is thrown. Since exceptions in C++ are supposed to be ''exceptional'' (i.e. uncommon/rare) events, the phrase "zero-cost exceptions"<ref group=note>There is "zero [processing] cost" only if no exception is throw (although there will be a memory cost since memory is needed for the lookup table). There is a (potentially significant) cost if an exception is thrown (that is, if <code>throw</code> is executed). Implementing exception handling may also limit the possible [[Optimizing compiler|compiler optimizations]] that may be performed.</ref> is sometimes used to describe exception handling in C++. Like [[runtime type identification]] (RTTI), exceptions might not adhere to C++'s [https://en.cppreference.com/w/cpp/language/Zero-overhead_principle zero-overhead principle] as implementing exception handling at run-time requires a non-zero amount of memory for the lookup table.<ref name=StroustrupExceptions2019>{{cite web|last=Stroustrup|first=Bjarne|author-link=Bjarne Stroustrup|title=C++ exceptions and alternatives|date=18 November 2019|access-date=23 March 2022|url=http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1947r0.pdf}}</ref> For this reason, exception handling (and RTTI) can be disabled in many C++ compilers, which may be useful for systems with very limited memory<ref name=StroustrupExceptions2019 /> (such as [[embedded system]]s). This second approach is also superior in terms of achieving [[thread safety]]{{Citation needed|date=September 2012}}.
In
Other definitional and implementation schemes have been proposed as well. For languages that support [[metaprogramming]], approaches that involve no overhead at all (beyond the already present support for [[reflection (computer science)|reflection]]) have been advanced.<ref>M. Hof, H. Mössenböck, P. Pirkelbauer, "[http://www.ssw.uni-linz.ac.at/Research/Papers/Hof97b.html Zero-Overhead Exception Handling Using Metaprogramming] {{webarchive|url=https://web.archive.org/web/20160303180327/http://www.ssw.uni-linz.ac.at/Research/Papers/Hof97b.html |date=2016-03-03 }}", ''Proceedings SOFSEM'97'', November 1997, ''Lecture Notes in Computer Science 1338'', pp. 423-431.</ref>
Line 141:
Although exceptions in Eiffel have a fairly clear philosophy, Kiniry (2006) criticizes their implementation because "Exceptions that are part of the language definition are represented by INTEGER values, developer-defined exceptions by STRING values. [...] Additionally, because they are basic values and not objects, they have no inherent semantics beyond that which is expressed in a helper routine which necessarily cannot be foolproof because of the representation overloading in effect (e.g., one cannot
differentiate two integers of the same value)."<ref name="Kiniry"/>
[[C++26]] adds support for contracts, which are used as follows.<ref>{{cite web|url=https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2900r14.pdf|title=Contracts for C++|date=13 February 2025}}</ref>
<syntaxhighlight lang="cpp">
int f(const int x)
pre(x != 1) // a precondition assertion
post(r : r == x && r != 2) // a postcondition assertion; r names the result object of f
{
contract_assert(x != 3); // an assertion statement
return x;
}
Each contract
</syntaxhighlight>
== Uncaught exceptions ==
Line 154 ⟶ 166:
== Checked exceptions ==
[[Java (programming language)|Java]] introduced the notion of checked exceptions,<ref>{{cite web |url=http://answers.google.com/answers/threadview?id=26101 |title=Google Answers: The origin of checked exceptions |access-date=2011-12-15 |url-status=live |archive-url=http://archive.wikiwix.com/cache/20110806090553/http://answers.google.com/answers/threadview?id=26101 |archive-date=2011-08-06 }}</ref><ref>Java Language Specification, chapter 11.2. http://java.sun.com/docs/books/jls/third_edition/html/exceptions.html#11.2 {{webarchive|url=https://web.archive.org/web/20061208042454/http://java.sun.com/docs/books/jls/third_edition/html/exceptions.html |date=2006-12-08 }}</ref> which are special classes of exceptions.
<syntaxhighlight lang="Java">
public void
// ...
}
Line 183 ⟶ 195:
* Scalability: In a hierarchical design, each systems may have several subsystems. Each subsystem may throw several exceptions. Each parent system must deal with the exceptions of all subsystems below it, resulting in an exponential number of exceptions to be dealt with. Checked exceptions require all of these exceptions to be dealt with explicitly.
To work around these, Hejlsberg says programmers resort to circumventing the feature by using a {{C++|throws Exception}} declaration. Another circumvention is to use a
=== Similar mechanisms ===
Line 189 ⟶ 201:
The roots of checked exceptions go back to the [[CLU programming language]]'s notion of exception specification.<ref name=Mindview/> A function could raise only exceptions listed in its type, but any leaking exceptions from called functions would automatically be turned into the sole runtime exception, {{code|failure}}, instead of resulting in compile-time error.<ref name="CLU">{{cite journal |last1=Liskov |first1=B.H. |last2=Snyder |first2=A. |title=Exception Handling in CLU |journal=IEEE Transactions on Software Engineering |date=November 1979 |volume=SE-5 |issue=6 |pages=546–558 |doi=10.1109/TSE.1979.230191 |s2cid=15506879 |url=http://csg.csail.mit.edu/CSGArchives/memos/Memo-155-3.pdf |access-date=19 December 2021}}</ref> Later, [[Modula-3]] had a similar feature.<ref>{{cite web |url=http://www1.cs.columbia.edu/graphics/modula3/tutorial/www/m3_23.html#SEC23 |title=Modula-3 - Procedure Types |publisher=.cs.columbia.edu |date=1995-03-08 |access-date=2011-12-15 |url-status=live |archive-url=https://web.archive.org/web/20080509143753/http://www1.cs.columbia.edu/graphics/modula3/tutorial/www/m3_23.html#SEC23 |archive-date=2008-05-09 }}</ref> These features don't include the compile time checking that is central in the concept of checked exceptions.<ref name=Mindview>{{cite web |url=http://www.mindview.net/Etc/Discussions/CheckedExceptions |archive-url=https://web.archive.org/web/20020405175011/http://www.mindview.net/Etc/Discussions/CheckedExceptions |url-status=dead |archive-date=2002-04-05 |title=Bruce Eckel's MindView, Inc: Does Java need Checked Exceptions? |publisher=Mindview.net |access-date=2011-12-15 }}</ref>
Early versions of the C++ programming language included an optional mechanism similar to checked exceptions, called '''exception specifications'''. By default any function could throw any exception, but this could be limited by a {{Cpp|throw}} clause (similar to the {{Java|throws}} clause in Java) added to the function signature, that specified which exceptions the function may throw.
Early versions of the C++ programming language included an optional mechanism similar to checked exceptions, called '''exception specifications'''. By default any function could throw any exception, but this could be limited by a {{Cpp|throw}} clause (similar to the <code>throws</code> clause in Java) added to the function signature, that specified which exceptions the function may throw. Exception specifications were not enforced at compile-time. Violations resulted in the global function {{Cpp|std::unexpected}} being called.<ref name=bjarne-exc>[[Bjarne Stroustrup]], ''[[The C++ Programming Language]]'' Third Edition, [[Addison Wesley]], 1997. {{ISBN|0-201-88954-4}}. pp. 375-380.</ref> An empty exception specification could be given, which indicated that the function will throw no exception. This was not made the default when exception handling was added to the language because it would have required too much modification of existing code, would have impeded interaction with code written in other languages, and would have tempted programmers into writing too many handlers at the local level.<ref name=bjarne-exc/> Explicit use of empty exception specifications could, however, allow C++ compilers to perform significant code and stack layout optimizations that are precluded when exception handling may take place in a function.<ref name=cppeh /> Some analysts viewed the proper use of exception specifications in C++ as difficult to achieve.<ref>{{cite journal | title=Ten Guidelines for Exception Specifications | last=Reeves | first= J.W. | journal=C++ Report | volume=8 | issue=7 |date=July 1996}}</ref> This use of exception specifications was included in [[C++98]] and [[C++03]], [[deprecated]] in the 2012 C++ language standard ([[C++11]]),<ref>{{cite web |url=http://herbsutter.com/2010/03/13/trip-report-march-2010-iso-c-standards-meeting/ |title=Trip Report: March 2010 ISO C++ Standards Meeting |last=Sutter |first=Herb |author-link=Herb Sutter |date=3 March 2010 |access-date=24 March 2010 |url-status=live |archive-url=https://web.archive.org/web/20100323082634/http://herbsutter.com/2010/03/13/trip-report-march-2010-iso-c-standards-meeting/ |archive-date=23 March 2010 }}</ref> and was removed from the language in [[C++17]]. Throws clauses were replaced by {{Cpp|noexcept}} clauses. A function that will not throw any exceptions would now be denoted by the {{Cpp|noexcept}} keyword, and instead {{Cpp|noexcept(false)}} specified that a function will throw. One can also specify that a function is <code>noexcept</code> conditionally on another function being <code>noexcept</code>, like so:▼
<syntaxhighlight lang="C++">
void performSomeOperation(int a, int b) throw(std::invalid_argument, std::domain_error) {
// ...
}
</syntaxhighlight>
C++ <code>throw</code> clauses could specify any number of any types, even primitives and classes that did not extend <code>std::exception</code>.
▲
<syntaxhighlight lang="C++">
#define throw(...) noexcept(false)
</syntaxhighlight>
One can also specify that a function is <code>noexcept</code> conditionally on another function being <code>noexcept</code>, like so:
<syntaxhighlight lang="C++">
void mightThrow();
// The first noexcept is the
void f() noexcept(noexcept(mightThrow()));
</syntaxhighlight>
Though C++ has no checked exceptions, one can propagate the thrown object up the stack when inside a <code>catch</code> block, by writing {{cpp|throw;}} (without specifying an object). This re-throws the caught object. This allows operations to be done within the <code>catch</code> block that catches it, before choosing to allow the object to continue propagating upwards.
An uncaught exceptions analyzer exists for the [[OCaml]] programming language.<ref>{{cite web |url=http://caml.inria.fr/pub/old_caml_site/ocamlexc/ocamlexc.htm |title=OcamlExc - An uncaught exceptions analyzer for Objective Caml |publisher=Caml.inria.fr |access-date=2011-12-15 |url-status=live |archive-url=http://archive.wikiwix.com/cache/20110806090555/http://caml.inria.fr/pub/old_caml_site/ocamlexc/ocamlexc.htm |archive-date=2011-08-06 }}</ref> The tool reports the set of raised exceptions as an extended type signature. But, unlike checked exceptions, the tool does not require any syntactic annotations and is external (i.e. it is possible to compile and run a program without having checked the exceptions).
In C++, one can also perform "Pokémon exception handling". Like <syntaxhighlight lang="java" inline>catch (Throwable t)</syntaxhighlight> in Java, C++ supports a <syntaxhighlight lang="cpp">catch (...)</syntaxhighlight> block, which will catch any thrown object. However, <code>catch (...)</code> has the disadvantage of not naming the caught object, which means it cannot be referred to.
<syntaxhighlight lang="cpp">
// Catching only exceptions:
try {
// ...
} catch (const std::exception& e) {
// Catching only exceptions:
std::println("An exception was caught: {}", e.what());
} catch (...) {
// Catching all thrown objects:
std::println("An unknown error was caught");
}
</syntaxhighlight>
The [[Rust (programming language)|Rust]] language, instead of using exceptions altogether, represents recoverable exceptions as [[result type]]s.<ref>{{cite web |title=std::result - Rust |url=https://doc.rust-lang.org/std/result/index.html |url-status=live |archive-url=https://web.archive.org/web/20231009032955/https://doc.rust-lang.org/std/result/index.html |archive-date=2023-10-09 |access-date=2023-10-09 |website=doc.rust-lang.org}}</ref><ref>{{cite web |date=2011-10-29 |title=stdlib: Add result module · rust-lang/rust@c1092fb |url=https://github.com/rust-lang/rust/commit/c1092fb6d88efe51e42df3aae2a321cc669e12a0 |url-status=live |archive-url=https://web.archive.org/web/20231009033047/https://github.com/rust-lang/rust/commit/c1092fb6d88efe51e42df3aae2a321cc669e12a0 |archive-date=2023-10-09 |access-date=2023-10-09 |website=github.com}}</ref> This is represented as <code>Result<T, E></code> (or <code>expected<T, E></code> in C++). The advantage of result types over checked exceptions is that while both result types and checked exceptions force users to immediately handle errors, they can also be directly represented as a return type within the language's type system, unlike checked exceptions where the declared potentially thrown exception is part of the function signature but not directly part of its return type.
== Dynamic checking of exceptions ==
|