{"id":105043,"date":"2021-04-01T07:00:00","date_gmt":"2021-04-01T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=105043"},"modified":"2021-04-01T08:09:19","modified_gmt":"2021-04-01T15:09:19","slug":"20210401-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20210401-00\/?p=105043","title":{"rendered":"C++ coroutines: What happens if an exception occurs in my return_value?"},"content":{"rendered":"<p>When I introduced <a title=\"C++ coroutines: Basic implementation of a promise type\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20210330-00\/?p=105019\"> a basic implementation of a promise type<\/a>, I noted that the <code>return_value<\/code> method or <code>return_void<\/code> method is called when the coroutine performs a <code>co_return<\/code>. But what happens if the <code>return_value<\/code> or <code>return_void<\/code> method raises an exception?<\/p>\n<pre>void return_value(T const&amp; v) const\r\n{\r\n    holder.set_result(v); \/\/ what if the copy constructor throws?\r\n}\r\n\r\nvoid unhandled_exception() const noexcept\r\n{\r\n    holder.set_exception(std::current_exception());\r\n}\r\n<\/pre>\n<p>What if we take an exception trying to set the result, say because the copy constructor threw an exception? Do we have to catch the exception and convert it to a <code>holder.set_exception<\/code>?<\/p>\n<pre>void return_value(T const&amp; v) const\r\n{\r\n    <span style=\"color: blue;\">\/\/ Do I have to wrap the set_result?<\/span>\r\n    <span style=\"color: blue;\">try {<\/span>\r\n        holder.set_result(v);\r\n    <span style=\"color: blue;\">} catch (...) {<\/span>\r\n        holder.set_exception(std::current_exception());\r\n    <span style=\"color: blue;\">}<\/span>\r\n}\r\n<\/pre>\n<p>Let&#8217;s go back and look at the transformation that the compiler performs when it generates a coroutine:<\/p>\n<pre>return_type MyCoroutine(args...)\r\n{\r\n    <i>create coroutine state<\/i>\r\n    <i>copy parameters to coroutine frame<\/i>\r\n    promise_type p;\r\n    auto return_object = p.get_return_object();\r\n\r\n    try {\r\n        co_await p.initial_suspend(); \/\/ \u00b9\r\n        <i>coroutine function body<\/i>\r\n    } catch (...) {\r\n        p.unhandled_exception();\r\n    }\r\n    co_await p.final_suspend();\r\n    <i>destruct promise p<\/i>\r\n    <i>destruct parameters in coroutine frame<\/i>\r\n    <i>destroy coroutine state<\/i>\r\n}\r\n<\/pre>\n<p>The <code>return_value<\/code> and <code>return_void<\/code> happen as part of the transformation of the <code>co_return<\/code> statement, and that is part of the section marked <i>coroutine function body<\/i>. Therefore, if an exception occurs during <code>return_value<\/code> or <code>return_void<\/code>, it is caught by the <code>catch (...)<\/code> and is delivered to <code>unhandled_exception<\/code>.<\/p>\n<p>In other words, the compiler already wrapped your <code>return_value<\/code> and <code>return_void<\/code> functions inside a <code>try<\/code>\/<code>catch<\/code> so you don&#8217;t have to.<\/p>\n<p>Note however that there is no <code>try<\/code>\/<code>catch<\/code> wrapped around the call to <code>unhandled_<wbr \/>exception<\/code>, so that method should be careful not throw any exceptions.<\/p>\n<p>Okay, so that was a brief digression on exceptions that occur when returning a value to the promise. Next time, we&#8217;ll look at another improvement to our coroutine promise implementation.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>What happens if you can&#8217;t save the result?<\/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-105043","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>What happens if you can&#8217;t save the result?<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/105043","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=105043"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/105043\/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=105043"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=105043"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=105043"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}