{"id":95915,"date":"2017-04-06T07:00:00","date_gmt":"2017-04-06T21:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/?p=95915"},"modified":"2019-03-13T01:09:14","modified_gmt":"2019-03-13T08:09:14","slug":"20170406-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20170406-00\/?p=95915","title":{"rendered":"What can I do if I want to throw a C++ exception from my InitOnce callback?"},"content":{"rendered":"<p>Suppose you want to use the <code>Init&shy;Once&shy;Execute&shy;Once<\/code> function to perform one-time initialization, but your initialization function might throw a C++ exception. We know that this is not allowed because <a HREF=\"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/20120910-00\/?p=6653\">you don&#8217;t control all the frames the exception is being thrown across<\/a>, so what are your options? <\/p>\n<p>The na&iuml;ve solution is to catch the exception before it escapes your callback, and then rethrow it on the other side. <\/p>\n<pre>\nvoid Sample()\n{\n    struct State {\n        std::exception_ptr p;\n        \/\/ other members you want to access from the lambda\n    } state;\n    if (!InitOnceExecuteOnce(&amp;g_InitOnce,\n          [](PINIT_ONCE InitOnce, void* Parameter, void** Context)\n          -&gt; BOOL\n          {\n              auto s = reinterpret_cast&lt;State*&gt;(Parameter);\n              try {\n                  init_stuff();\n                  return TRUE;\n              } catch (std::exception&amp; e) {\n                  s-&gt;p = std::current_exception();\n                  return FALSE;\n              }\n          }, &amp;state, nullptr)) {\n        \/\/ Failed due to exception.  Rethrow now that we are\n        \/\/ safely outside the InitOnceExecuteOnce function.\n        std::rethrow_exception(state.p);\n    }\n}\n<\/pre>\n<p>A less cumbersome solution is to use <a HREF=\"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/20161222-00\/?p=94995\">synchronous two-phase initialization<\/a>: <\/p>\n<pre>\nvoid Sample()\n{\n    void* result;\n    BOOL pending;\n    if (!InitOnceBeginInitialize(&amp;g_InitOnce, 0,\n                                 &amp;pending, &amp;result)) {\n        if (pending) {\n            try {\n                init_stuff();\n            } catch (...) {\n                InitOnceComplete(&amp;g_InitOnce,\n                                 INIT_ONCE_INIT_FAILED, result);\n                throw;\n            }\n            InitOnceComplete(&amp;g_InitOnce, 0, result);\n        }\n    }\n}\n<\/pre>\n<p>Synchronous two-phase initialization performs the initialization inline rather than in a callback, which saves you the trouble of having to save the exception in one place and rethrow it in another place. You can just tell the InitOnce engine that initialization failed and then allow the exception to propagate. <\/p>\n<p>You might decide to wrap this pattern inside an RAII type. <\/p>\n<pre>\nclass InitOnceGuard\n{\npublic:\n    InitOnceGuard(PINIT_ONCE initOnce) :\n        m_initOnce(initOnce),\n        m_success(InitOnceBeginInitialize(initOnce, 0, &amp;m_pending, nullptr)),\n        m_status(INIT_ONCE_INIT_FAILED)\n    {\n    }\n\n    ~InitOnceGuard()\n    {\n        if (NeedInitialization()) InitOnceComplete(m_initOnce, m_status, nullptr);\n    }\n\n    InitOnceGuard(const InitOnceGuard&amp;) = delete;\n    InitOnceGuard(InitOnceGuard&amp;&amp;) = delete;\n    InitOnceGuard&amp; operator=(const InitOnceGuard&amp;) = delete;\n    InitOnceGuard&amp; operator=(const InitOnceGuard&amp;&amp;) = delete;\n\n    bool NeedInitialization() { return m_success &amp;&amp; m_pending; }\n\n    \/\/ If you don't Complete, then the guard assumes that initialization failed.\n    void Complete() { m_status = 0; }\n\nprivate:\n    PINIT_ONCE m_initOnce;\n    bool m_success;\n    bool m_pending;\n    DWORD m_status;\n}\n\nvoid Sample()\n{\n    InitOnceGuard guard(&amp;g_InitOnce);\n    if (guard.NeedInitialization()) {\n        init_stuff();\n        guard.Complete();\n    }\n}\n<\/pre>\n<p>If the <code>guard<\/code> destructs without ever being <code>Complete<\/code>d, either because of an exception, or because the caller decided that initialization failed in an unexceptional way, then the destructor will tell the InitOnce engine that initialization failed. This will unblock any other threads that are waiting for initialization to complete and allow them to give it a try. <\/p>\n<p>If the <code>guard<\/code> is <code>Complete<\/code>d, then its destructor tells the InitOnce engine that initialization was successful. <\/p>\n<p>After thinking about all that, you might realize that the fact that you&#8217;re throwing C++ exceptions means that you&#8217;re already committed to C++, so you may as well go all in: Use <code>std::call_once<\/code> or C++ static locals. These are part of the C++ standard and are fully exception-aware. Of course, it assumes that all the frames you are throwing across came from the same C++ compiler. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>There&#8217;s the na&iuml;ve solution and a sneakier one.<\/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-95915","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>There&#8217;s the na&iuml;ve solution and a sneakier one.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/95915","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=95915"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/95915\/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=95915"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=95915"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=95915"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}