|
| 1 | +--- |
| 2 | +title: Handling exceptions |
| 3 | +sidebar: |
| 4 | + order: 4 |
| 5 | +--- |
| 6 | + |
| 7 | +import { Decl, DeclDoc } from "@components/decl-doc"; |
| 8 | +import { Desc, DescList, DocLink } from '@components/index'; |
| 9 | +import { Revision, RevisionBlock } from "@components/revision"; |
| 10 | +import { DR, DRList } from "@components/defect-report"; |
| 11 | +import { ParamDoc, ParamDocList } from "@components/param-doc"; |
| 12 | + |
| 13 | +An <DocLink dest="/cpp/language/exceptions">exception</DocLink> can be handled by a handler. |
| 14 | + |
| 15 | +### Handler |
| 16 | + |
| 17 | +<DeclDoc id={1}> |
| 18 | + <Decl slot="decl"> |
| 19 | + ```cpp cxx-mark |
| 20 | + catch ( /*$s:attr*//*$opt*/ /*$s:type-specifier-seq*/ /*$s:declarator*/ ) /*$s:compound-statement*/ |
| 21 | + ``` |
| 22 | + </Decl> |
| 23 | + A handler with a named parameter. |
| 24 | +</DeclDoc> |
| 25 | +<DeclDoc id={2}> |
| 26 | + <Decl slot="decl"> |
| 27 | + ```cpp cxx-mark |
| 28 | + catch ( /*$s:attr*//*$opt*/ /*$s:type-specifier-seq*/ /*$s:abstract-declarator*//*$opt*/ ) /*$s:compound-statement*/ |
| 29 | + ``` |
| 30 | + </Decl> |
| 31 | + A handler with an unnamed parameter. |
| 32 | +</DeclDoc> |
| 33 | +<DeclDoc id={3}> |
| 34 | + <Decl slot="decl"> |
| 35 | + ```cpp cxx-mark |
| 36 | + catch ( ... ) /*$s:compound-statement*/ |
| 37 | + ``` |
| 38 | + </Decl> |
| 39 | + A handler matching all kinds of exceptions. |
| 40 | +</DeclDoc> |
| 41 | + |
| 42 | +<ParamDocList> |
| 43 | + <ParamDoc name="attr"> |
| 44 | + <Revision since="C++11"></Revision> any number of <DocLink dest="/cpp/language/attributes">attributes</DocLink>, applies to the parameter |
| 45 | + </ParamDoc> |
| 46 | + <ParamDoc name="type-specifier-seq"> |
| 47 | + part of a formal parameter declaration, same as in a function <DocLink dest="/cpp/language/functions/function#Parameter_list">parameter list</DocLink> |
| 48 | + </ParamDoc> |
| 49 | + <ParamDoc name="declarator"> |
| 50 | + part of a parameter declaration, same as in a function <DocLink dest="/cpp/language/functions/function#Parameter_list">parameter list</DocLink> |
| 51 | + </ParamDoc> |
| 52 | + <ParamDoc name="abstract-declarator"> |
| 53 | + part of an unnamed parameter declaration, same as in function <DocLink dest="/cpp/language/functions/function#Parameter_list">parameter list</DocLink> |
| 54 | + </ParamDoc> |
| 55 | + <ParamDoc name="compound-statement"> |
| 56 | + a <DocLink dest="/cpp/language/statements#Compound_statements">compound statement</DocLink> |
| 57 | + </ParamDoc> |
| 58 | + </ParamDocList> |
| 59 | + |
| 60 | + The parameter declaration in a handler describes the type(s) of exceptions that can cause that handler to be entered. |
| 61 | + |
| 62 | + If the parameter is declared to have one of the following types, the program is ill-formed: |
| 63 | + |
| 64 | + - an <DocLink dest="/cpp/language/basic_concepts/definition#Incomplete_type">incomplete type</DocLink> |
| 65 | + - an <DocLink dest="/cpp/language/classes#Abstract_classes">abstract class type</DocLink> |
| 66 | + - an <DocLink dest="/cpp/language/reference#Rvalue_reference"><Revision since="C++11">rvalue reference type</Revision></DocLink> |
| 67 | + - a pointer to an incomplete type other than (possibly cv-qualified) `void` |
| 68 | + - an lvalue reference to an incomplete type |
| 69 | + |
| 70 | + If the parameter is declared to have type “array of `T`” or function type `T`, the type is adjusted to “pointer to `T`”. |
| 71 | + |
| 72 | + A handler with parameter type `T` can be abbreviated as “a handler of type `T`”. |
| 73 | + |
| 74 | + ### Matching exceptions |
| 75 | + |
| 76 | + Each `try` block associates with a number of handlers, these handlers form a handler sequence. When an exception is thrown from a `try` block, the handlers in the sequence are tried in order of appearance to match the exception. |
| 77 | + |
| 78 | + A handler is a match for an <DocLink dest="/cpp/language/exceptions/throwing_exceptions#Exception_object">exception object</DocLink> of type `E` if any of the following conditions is satisfied: |
| 79 | + |
| 80 | + - The handler is of type “possibly cv-qualified `T`” or “lvalue reference to possibly cv-qualified `T`”, and any of the following conditions is satisfied: |
| 81 | + - `E` and `T` are the same type (ignoring the top-level cv-qualifiers). |
| 82 | + - `T` is an unambiguous public base class of `E`. |
| 83 | + - The handler is of type “possibly cv-qualified `T`” or `const T&` where `T` is a pointer or pointer-to-member type, and any of the following conditions is satisfied: |
| 84 | + - `E` is a pointer or pointer-to-member type that can be converted to `T` by at least one of the following conversions: |
| 85 | + - A <DocLink dest="/cpp/language/implicit_cast#Pointer_conversions">standard pointer conversion</DocLink> not involving conversions to pointers to private or protected or ambiguous classes. |
| 86 | + - <Revision since="C++17">A <DocLink dest="/cpp/language/implicit_cast#Function_pointer_conversions">function pointer conversion.</DocLink></Revision> |
| 87 | + - A <DocLink dest="/cpp/language/implicit_cast#Qualification_conversions">qualification conversion</DocLink>. |
| 88 | + - <Revision since="C++11">`E` is <DocLink dest="/cpp/types/nullptr_t">std::nullptr_t</DocLink>.</Revision> |
| 89 | + |
| 90 | + The `catch (...)` handler matches exceptions of any type. If present, it can only be the last handler in a handler sequence. This handler may be used to ensure that no uncaught exceptions can possibly escape from a function that offers <DocLink dest="/cpp/language/exceptions">nothrow exception guarantee</DocLink>. |
| 91 | + |
| 92 | + ```cpp |
| 93 | + try |
| 94 | + { |
| 95 | + f(); |
| 96 | + } |
| 97 | + catch (const std::overflow_error& e) |
| 98 | + {} // this executes if f() throws std::overflow_error (same type rule) |
| 99 | + catch (const std::runtime_error& e) |
| 100 | + {} // this executes if f() throws std::underflow_error (base class rule) |
| 101 | + catch (const std::exception& e) |
| 102 | + {} // this executes if f() throws std::logic_error (base class rule) |
| 103 | + catch (...) |
| 104 | + {} // this executes if f() throws std::string or int or any other unrelated type |
| 105 | + ``` |
| 106 | + |
| 107 | + If no match is found among the handlers for a `try` block, the search for a matching handler continues in a dynamically surrounding `try` block<Revision since="C++11"> of the same thread</Revision>. |
| 108 | + |
| 109 | + If no matching handler is found, <DocLink dest="/cpp/error/terminate">std::terminate</DocLink> is invoked; whether or not the stack is <DocLink dest="/cpp/language/exceptions/throwing_exceptions#Stack_unwinding">unwound</DocLink> before this invocation of <DocLink dest="/cpp/error/terminate">std::terminate</DocLink> is implementation-defined. |
| 110 | + |
| 111 | + ### Handling exceptions |
| 112 | + |
| 113 | + When an exception is thrown, control is transferred to the nearest handler with a matching type; “nearest” means the handler for which the compound statement or the member initializer list (if present) following the `try` keyword was most recently entered by the thread of control and not yet exited. |
| 114 | + |
| 115 | + #### Initializing the handler parameter |
| 116 | + |
| 117 | + The parameter declared in the parameter list (if any), of type “possibly cv-qualified `T`” or “lvalue reference to possibly cv-qualified `T`”, is initialized from the <DocLink dest="/cpp/language/exceptions/throwing_exceptions#Exception_object">exception object</DocLink>, of type `E`, as follows: |
| 118 | + |
| 119 | + - If `T` is a base class of `E`, the parameter is <DocLink dest="/cpp/language/copy_initialization">copy-initialized</DocLink> from an lvalue of type `T` designating the corresponding base class subobject of the exception object. |
| 120 | + - Otherwise, the parameter is copy-initialized from an lvalue of type `E` designating the exception object. |
| 121 | + |
| 122 | + The lifetime of the parameter ends when the handler exits, after the destruction of any objects with automatic <DocLink dest="/cpp/language/storage_duration">storage duration</DocLink> initialized within the handler. |
| 123 | + |
| 124 | + When the parameter is declared as an object, any changes to that object will not affect the exception object. |
| 125 | + |
| 126 | + When the parameter is declared as a reference to an object, any changes to the referenced object are changes to the exception object and will have effect should that object be rethrown. |
| 127 | + |
| 128 | + #### Activating the handler |
| 129 | + |
| 130 | + A handler is considered _active_ when initialization is complete for the parameter (if any) of the handler. |
| 131 | + |
| 132 | + Also, an implicit handler is considered active when <DocLink dest="/cpp/error/terminate">std::terminate</DocLink> is entered due to a throw. |
| 133 | + |
| 134 | + A handler is no longer considered active when the handler exits. |
| 135 | + |
| 136 | + The exception with the most recently activated handler that is still active is called the _currently handled exception_. Such an exception can be <DocLink dest="/cpp/language/exceptions/throwing_exceptions#throw_expressions">rethrown</DocLink>. |
| 137 | + |
| 138 | + ### Control flow |
| 139 | + |
| 140 | + The `compound-statement` of a handler is a <DocLink dest="/cpp/language/statements#Control-flow-limited_statements">control-flow-limited statement</DocLink>: |
| 141 | + |
| 142 | + ```cpp |
| 143 | + void f() |
| 144 | + { |
| 145 | + goto label; // error |
| 146 | + try |
| 147 | + { |
| 148 | + goto label; // error |
| 149 | + } |
| 150 | + catch (...) |
| 151 | + { |
| 152 | + goto label: // OK |
| 153 | + label: ; |
| 154 | + } |
| 155 | + } |
| 156 | + ``` |
| 157 | + |
| 158 | + ### Notes |
| 159 | + |
| 160 | + <DocLink dest="/cpp/language/exceptions/throwing_exceptions#Stack_unwinding">Stack unwinding</DocLink> occurs while control is transferring to a handler. When a handler becomes active, stack unwinding is already completed. |
| 161 | + |
| 162 | + The exception thrown by the `throw` expression `throw 0` does not match a handler of pointer or pointer-to-member type. |
| 163 | + |
| 164 | + - <Revision since="C++11">`throw nullptr` can be used instead to throw a null pointer that matches such handlers.</Revision> |
| 165 | + |
| 166 | + <DocLink dest="/cpp/language/exceptions/throwing_exceptions#Exception_object">Exception objects</DocLink> can never have array or function types, therefore a handler of reference to array or function type is never a match for any exception object. |
| 167 | + |
| 168 | + It is possible to write handlers that can never be executed, for example by placing a handler for a final derived class after a handler for a corresponding unambiguous public base class: |
| 169 | + |
| 170 | + ```cpp |
| 171 | + try |
| 172 | + { |
| 173 | + f(); |
| 174 | + } |
| 175 | + catch (const std::exception& e) |
| 176 | + {} // will be executed if f() throws std::runtime_error |
| 177 | + catch (const std::runtime_error& e) |
| 178 | + {} // dead code! |
| 179 | + ``` |
| 180 | + |
| 181 | + Many implementations overly extend the resolution of <DocLink dest="https://cplusplus.github.io/CWG/issues/388.html">CWG issue 388</DocLink> to handlers of reference to non-const pointer types: |
| 182 | + |
| 183 | + ```cpp |
| 184 | + int i; |
| 185 | + try |
| 186 | + { |
| 187 | + try |
| 188 | + { |
| 189 | + throw static_cast<float*>(nullptr); |
| 190 | + } |
| 191 | + catch (void*& pv) |
| 192 | + { |
| 193 | + pv = &i; |
| 194 | + throw; |
| 195 | + } |
| 196 | + } |
| 197 | + catch (const float* pf) |
| 198 | + { |
| 199 | + assert(pf == nullptr); // should pass, but fails on MSVC and Clang |
| 200 | + } |
| 201 | + ``` |
| 202 | + |
| 203 | + ### Keywords |
| 204 | + |
| 205 | + - <DocLink dest="/cpp/keyword/catch">`catch`</DocLink> |
| 206 | + |
| 207 | + ### Example |
| 208 | + |
| 209 | + The following example demonstrates several usage cases of the handlers: |
| 210 | + |
| 211 | + ```cpp |
| 212 | + #include <iostream> |
| 213 | + #include <vector> |
| 214 | + |
| 215 | + int main() |
| 216 | + { |
| 217 | + try |
| 218 | + { |
| 219 | + std::cout << "Throwing an integer exception...\n"; |
| 220 | + throw 42; |
| 221 | + } |
| 222 | + catch (int i) |
| 223 | + { |
| 224 | + std::cout << " the integer exception was caught, with value: " << i << '\n'; |
| 225 | + } |
| 226 | + |
| 227 | + try |
| 228 | + { |
| 229 | + std::cout << "Creating a vector of size 5... \n"; |
| 230 | + std::vector<int> v(5); |
| 231 | + std::cout << "Accessing the 11th element of the vector...\n"; |
| 232 | + std::cout << v.at(10); // vector::at() throws std::out_of_range |
| 233 | + } |
| 234 | + catch (const std::exception& e) // caught by reference to base |
| 235 | + { |
| 236 | + std::cout << " a standard exception was caught, with message: '" |
| 237 | + << e.what() << "'\n"; |
| 238 | + } |
| 239 | + } |
| 240 | + ``` |
| 241 | + |
| 242 | + Possible output: |
| 243 | + |
| 244 | + ```text |
| 245 | + Throwing an integer exception... |
| 246 | + the integer exception was caught, with value: 42 |
| 247 | + Creating a vector of size 5... |
| 248 | + Accessing the 11th element of the vector... |
| 249 | + a standard exception was caught, with message: 'out_of_range' |
| 250 | + ``` |
| 251 | + |
| 252 | + ### Defect reports |
| 253 | + |
| 254 | + The following behavior-changing defect reports were applied retroactively to previously published C++ standards. |
| 255 | + |
| 256 | + <DRList> |
| 257 | + <DR kind="cwg" id={98} std="C++98"> |
| 258 | + <Fragment slot="behavior-published"> |
| 259 | + a `switch` statement can transfer control into a handler |
| 260 | + </Fragment> |
| 261 | + <Fragment slot="correct-behavior"> |
| 262 | + prohibited |
| 263 | + </Fragment> |
| 264 | + </DR> |
| 265 | + <DR kind="cwg" id={210} std="C++98"> |
| 266 | + <Fragment slot="behavior-published"> |
| 267 | + `throw` expressions were matched against the handlers |
| 268 | + </Fragment> |
| 269 | + <Fragment slot="correct-behavior"> |
| 270 | + exception objects are matched against the handlers |
| 271 | + </Fragment> |
| 272 | + </DR> |
| 273 | + <DR kind="cwg" id={388} std="C++98"> |
| 274 | + <Fragment slot="behavior-published"> |
| 275 | + an exception of pointer or pointer to member type could not be matched by a const reference to a different type |
| 276 | + </Fragment> |
| 277 | + <Fragment slot="correct-behavior"> |
| 278 | + made matchable when convertible |
| 279 | + </Fragment> |
| 280 | + </DR> |
| 281 | + <DR kind="cwg" id={1166} std="C++98"> |
| 282 | + <Fragment slot="behavior-published"> |
| 283 | + the behavior was unspecified when a handler whose type is a reference to an abstract class type is matched |
| 284 | + </Fragment> |
| 285 | + <Fragment slot="correct-behavior"> |
| 286 | + abstract class types are not allowed for handlers |
| 287 | + </Fragment> |
| 288 | + </DR> |
| 289 | + <DR kind="cwg" id={1769} std="C++98"> |
| 290 | + <Fragment slot="behavior-published"> |
| 291 | + when the type of the handler is a base of the type of the exception object, a converting constructor might be used for the initialization of the handler parameter |
| 292 | + </Fragment> |
| 293 | + <Fragment slot="correct-behavior"> |
| 294 | + the parameter is copy-initialized from the corresponding base class subobject of the exception object |
| 295 | + </Fragment> |
| 296 | + </DR> |
| 297 | + <DR kind="cwg" id={2093} std="C++98"> |
| 298 | + <Fragment slot="behavior-published"> |
| 299 | + an exception object of pointer to object type could not match a handler of pointer to object type through qualification conversion |
| 300 | + </Fragment> |
| 301 | + <Fragment slot="correct-behavior"> |
| 302 | + allowed |
| 303 | + </Fragment> |
| 304 | + </DR> |
| 305 | + </DRList> |
| 306 | + |
| 307 | + ### References |
| 308 | + |
| 309 | + - C++23 standard (ISO/IEC 14882:2024): |
| 310 | + - 14.4 Handling an exception [except.handle] |
| 311 | + - C++20 standard (ISO/IEC 14882:2020): |
| 312 | + - 14.4 Handling an exception [except.handle] |
| 313 | + - C++17 standard (ISO/IEC 14882:2017): |
| 314 | + - 18.3 Handling an exception [except.handle] |
| 315 | + - C++14 standard (ISO/IEC 14882:2014): |
| 316 | + - 15.3 Handling an exception [except.handle] |
| 317 | + - C++11 standard (ISO/IEC 14882:2011): |
| 318 | + - 15.3 Handling an exception [except.handle] |
| 319 | + - C++03 standard (ISO/IEC 14882:2003): |
| 320 | + - 15.3 Handling an exception [except.handle] |
| 321 | + - C++98 standard (ISO/IEC 14882:1998): |
| 322 | + - 15.3 Handling an exception [except.handle] |
| 323 | + |
| 324 | + ### See also |
| 325 | + |
| 326 | + - <DocLink dest="/cpp/language/exceptions/try">`try` block</DocLink> |
| 327 | + - <DocLink dest="/cpp/language/exceptions/throw">Throwing exceptions</DocLink> |
| 328 | + - <DocLink dest="/cpp/error">Exception handling</DocLink> |
0 commit comments