{"id":107307,"date":"2022-10-21T07:00:00","date_gmt":"2022-10-21T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=107307"},"modified":"2022-10-21T08:37:59","modified_gmt":"2022-10-21T15:37:59","slug":"20221021-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20221021-00\/?p=107307","title":{"rendered":"What happens if my C++ exception handler itself raises an exception?"},"content":{"rendered":"<p>Last time, we looked at <a title=\"Is it true that raising a structured exception from a structured exception handler terminates the process?\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20221020-00\/?p=107303\"> what happens if your structured exception handler raises its own structured exception<\/a>. Today, we&#8217;ll look at the C++ version of the same question: What happens if my C++ exception handler itself raises an exception?<\/p>\n<p>Let&#8217;s look at this sample code fragment:<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td>\n<pre>try\r\n{\r\n    Block1;\r\n}\r\ncatch (Type1 ex1)\r\n{\r\n    Block2;\r\n}\r\ncatch (Type2 const&amp; ex2)\r\n{\r\n    Block3;\r\n}\r\n\/* finally { destructors; } *\/<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>If an exception is thrown out of <code>Block1<\/code>, C++ looks for a matching <code>catch<\/code> block,\u00b9 and neither clause matches, then the search for a handler continues at the next outer scope. If no scope handles the exception, then the process terminates via <code>std::terminate<\/code>.<\/p>\n<p>The bodies of the <code>catch<\/code> blocks are not in scope of the <code>try<\/code> statement, so if an exception is thrown by <code>Block2<\/code> or <code>Block3<\/code>, the search for a handler does not include the <code>catch (Type1 ex1)<\/code> or <code>catch (Type2 const&amp; ex1)<\/code> clauses.<\/p>\n<p>There is no <code>finally<\/code> clause in C++ <code>try<\/code>\/<code>catch<\/code> statements, but the equivalent functionality is obtained by putting the desired cleanup code in destructors of objects declared in <code>Block1<\/code>. If control exits <code>Block1<\/code> due to an exception, and one of the objects in that block throws an exception in its destructor, then the rules of C++ are that the process terminates immediately via <code>std::terminate<\/code>. This is different from Windows structured exceptions and C# exceptions.<\/p>\n<p>In the code sample above, I&#8217;ve put these destructors in a pseudo-&#8220;finally&#8221; clause, just so I will have a place to annotate them.<\/p>\n<p>Another difference from Windows structured exceptions is the case of an exception that occurs while performing type matching: If a <code>catch<\/code> clause captures the exception object by value, the exception object is constructed from the thrown object. And if that constructor throws an exception, the C++ standard says that the process terminates via <code>std::terminate<\/code>.\u00b2 (This is also different from Windows structured exceptions.)<\/p>\n<p>Here&#8217;s an annotated version of the above discussion:<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td style=\"border: solid 1px gray; border-right: none;\">\n<pre>try\r\n{\r\n    Block1;\r\n}<\/pre>\n<\/td>\n<td style=\"border: solid 1px gray; border-left: none; margin-right: 1ex;\">Under consideration<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px gray; border-right: none;\">\n<pre>catch (Type1 ex1)<\/pre>\n<\/td>\n<td style=\"border: solid 1px gray; border-left: none; margin-right: 1ex;\"><code>std::terminate<\/code><\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px gray; border-right: none;\">\n<pre>{\r\n    Block2;\r\n}<\/pre>\n<\/td>\n<td style=\"border: solid 1px gray; border-left: none; margin-right: 1ex;\">Not considered<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px gray; border-right: none;\">\n<pre>catch (Type2 const&amp; ex2)<\/pre>\n<\/td>\n<td style=\"border: solid 1px gray; border-left: none; margin-right: 1ex;\"><code>std::terminate<\/code><\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px gray; border-right: none;\">\n<pre>{\r\n    Block3;\r\n}<\/pre>\n<\/td>\n<td style=\"border: solid 1px gray; border-left: none; margin-right: 1ex;\">Not considered<\/td>\n<td rowspan=\"2\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px gray; border-right: none;\">\n<pre>\/* finally { destructors; } *\/<\/pre>\n<\/td>\n<td style=\"border: solid 1px gray; border-left: none; margin-right: 1ex;\">It&#8217;s complicated<\/td>\n<td rowspan=\"2\">\u00a0<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>The &#8220;It&#8217;s complicated&#8221; for the pseudo-finally clause applies because both behaviors are possible, depending on why the destructors are running.<\/p>\n<ul>\n<li>If <code>Block1<\/code> is exiting normally, then exceptions that occur in destructors are catchable by the <code>try<\/code> statement.<\/li>\n<li>If <code>Block1<\/code> is exiting due to an exception, then <code>std::terminate<\/code> is called.<\/li>\n<\/ul>\n<p>Note that both cases can occur in the same <code>try<\/code> statement! Suppose the <code>Block1<\/code> runs to the final close-brace, and then it becomes time to run the destructors. Suppose there are two objects inside the <code>Block1<\/code> that require destruction. The first one to destruct throws an exception. This is an exception thrown during normal exit of <code>Block1<\/code>, so the exception is catchable. But before we try to catch that exception, we need to run the second destructor. If this second destructor also throws an exception, we are now in the case of a destructor throwing an exception during exception handling, and this results in <code>std::terminate<\/code>.<\/p>\n<p>\u00b9 This search is done sequentially, so it will try to match <code>Type1<\/code> first, and <code>Type2 const&amp;<\/code> second. As a result, reordering your <code>catch<\/code> clauses can result in changes in behavior if the thrown object matches multiple <code>catch<\/code> clauses.<\/p>\n<p>\u00b2 In general, you should catch things by reference. This removes the possibility of exceptions during the construction of the <code>catch<\/code> argument, and it also avoids slicing if the thrown object is a derived class of the thing you&#8217;re catching.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>And comparing to the handling of structured exceptions.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-107307","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>And comparing to the handling of structured exceptions.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/107307","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=107307"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/107307\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=107307"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=107307"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=107307"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}