{"id":105153,"date":"2021-04-26T07:00:00","date_gmt":"2021-04-26T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=105153"},"modified":"2021-04-26T07:10:53","modified_gmt":"2021-04-26T14:10:53","slug":"20210426-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20210426-00\/?p=105153","title":{"rendered":"C++ coroutines: What does it mean when I declare my coroutine as noexcept?"},"content":{"rendered":"<p>Suppose you want a coroutine that terminates on unhandled exceptions, or equivalently (looking at it from the consumer side) a coroutine that never throws an exception when awaited. For regular functions, the way to say this is to put the <code>noexcept<\/code> exception specification on your function declaration:<\/p>\n<pre>int GetValue() noexcept\r\n{\r\n    return LoadValue();\r\n}\r\n<\/pre>\n<p>If the <code>Load\u00adValue()<\/code> function raises an exception, the exception propagation stops at the <code>noexcept<\/code> and turns into a <code>std::terminate<\/code>, which is a fatal error that terminates the application.<\/p>\n<p>Looking at the contract from the other side, the <code>noexcept<\/code> specification tells the caller that no exceptions can escape the <code>Get\u00adValue()<\/code> function, so the caller can optimize accordingly. <code>Get\u00adValue()<\/code> will get you a value or die trying.<\/p>\n<p>Okay, so what happens when you apply this to a coroutine?<\/p>\n<pre>simple_task&lt;int&gt; GetValueAsync() noexcept\r\n{\r\n    co_return LoadValue();\r\n}\r\n<\/pre>\n<p>If an exception is thrown by the <code>Load\u00adValue()<\/code> function, the exception is captured into the <code>simple_task<\/code> and is rethrown when the task is <code>co_await<\/code>ed.<\/p>\n<p>Wait a second. I put the <code>noexcept<\/code> keyword on this function. Certainly that means that any unhandled exception in the function terminates the program, right?<\/p>\n<p>Yes, that&#8217;s what it means, but your coroutine isn&#8217;t the function.<\/p>\n<p>The function is the thing that returns a <code>simple_task<\/code>. And the <code>noexcept<\/code> says that the <code>Get\u00adValue\u00adAsync()<\/code> function can successfully return a <code>simple_task<\/code> without raising an exception.<\/p>\n<p>Look at this from the caller&#8217;s point of view: The caller sees only<\/p>\n<pre>simple_task&lt;int&gt; GetValueAsync() noexcept;\r\n<\/pre>\n<p>This is not a coroutine definition. This is just a function prototype. The caller doesn&#8217;t know how GetValueAsync() is going to produce that <code>simple_task<\/code>. The implementation could be<\/p>\n<pre>simple_task&lt;int&gt; GetValueAsync() noexcept\r\n{\r\n    return simple_task&lt;int&gt;(constructor parameters);\r\n}\r\n<\/pre>\n<p>Just the usual case of returning a constructed object. No coroutines involved at all.<\/p>\n<p>If <code>Get\u00adValue\u00adAsync()<\/code> is implemented as a coroutine, then any unhandled exception is passed to the coroutine promise&#8217;s <code>unhandled_<wbr \/>exception<\/code> method, and it&#8217;s up to the promise to decide what to do next.<\/p>\n<p>So what can you do if you really want your coroutine to terminate on unhandled exception? We&#8217;ll look at that next time.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The noexcept keyword doesn&#8217;t mean what you think.<\/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-105153","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>The noexcept keyword doesn&#8217;t mean what you think.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/105153","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=105153"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/105153\/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=105153"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=105153"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=105153"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}