{"id":96515,"date":"2017-07-03T07:00:00","date_gmt":"2017-07-03T21:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/?p=96515"},"modified":"2019-03-13T01:13:43","modified_gmt":"2019-03-13T08:13:43","slug":"20170703-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20170703-00\/?p=96515","title":{"rendered":"Emulating the C# <CODE>using<\/CODE> keyword in C++"},"content":{"rendered":"<p>C# has a very convenient <code>using<\/code> statement which ensures that an object is <code>Dispose()<\/code>d when control exits the block. C++ has a generalization of this concept with RAII types, but things get tricky when you have tasks, lambda capture, and the need to explicitly <code>Close()<\/code> the hat pointer. <\/p>\n<p>Here we go. <\/p>\n<p>Here&#8217;s one attempt, for C++\/CX hat pointers: <\/p>\n<pre>\ntemplate&lt;typename T&gt;\nclass unique_close\n{\npublic:\n  unique_close(T^ t) : m_t(t) { }\n  ~unique_close() { delete m_t; }\n\n  \/\/ Disallow copying\n  unique_close(const unique_close&amp; other) = delete;\n  unique_close&amp; operator=(const unique_close&amp; other) = delete;\n\n  \/\/ Moving transfers the obligation to Close\n  unique_close(unique_close&amp;&amp; other)\n  {\n    *this = std::move(other);\n  }\n  unique_close&amp; operator=(unique_close&amp;&amp; other)\n  {\n    using std::swap; \/\/ enable ADL on the swap\n    swap(m_t, other.m_t);\n    return *this;\n  }\n\nprivate:\n  T^ m_t;\n};\n\ntemplate&lt;typename T&gt;\nauto make_unique_close(T^ t)\n{\n  return unique_close&lt;T&gt;(t);\n}\n<\/pre>\n<p>With explicit task chaining, you need to remember to use <code>std::<\/code><code>move<\/code> to move the <code>unique_close<\/code> object into the final task in the chain if you didn&#8217;t construct it directly in the capture. If you forget to do this, then the destruction of the <code>unique_close<\/code> objects in the main function will close the objects prematurely because they are still in control. <\/p>\n<pre>\nvoid Scenario1_Render::ViewPage()\n{\n    ...\n\n    if (outfile)\n    {\n        auto page = pdfDocument-&gt;GetPage(pageIndex);\n\n        return create_task(outfile-&gt;OpenTransactedWriteAsync())\n            .then([this, page, <font COLOR=\"blue\">usingPage{make_unique_close(page)}<\/font>]\n                  (StorageStreamTransaction^ transaction) <font COLOR=\"blue\">mutable<\/font>\n        {\n            auto options = ref new PdfPageRenderOptions();\n            options-&gt;DestinationHeight = (unsigned)(page-&gt;Size.Height * 2);\n            options-&gt;DestinationWidth = (unsigned)(page-&gt;Size.Width * 2);\n            create_task(page-&gt;RenderToStreamAsync(transaction-&gt;Stream, options))\n                .then([this, <font COLOR=\"blue\">usingPage{std::move(usingPage)},\n                       usingTransaction{make_unique_close(transaction)}<\/font>]() <font COLOR=\"blue\">mutable<\/font>\n            {\n                <font COLOR=\"blue\">\/\/ destruction of usingPage and usingTransaction\n                \/\/ will close the page and transaction.<\/font>\n            });\n        });\n    }\n    ...\n}\n<\/pre>\n<p>(Let us ignore the fact that this doesn&#8217;t work because <code>task::<\/code><code>then<\/code> requires a copyable lambda, and ours is merely movable.) <\/p>\n<p>One way to address the added cognitive burden of having to remember to <a HREF=\"http:\/\/tvtropes.org\/pmwiki\/pmwiki.php\/Main\/MoveAlongNothingToSeeHere\">keep moving<\/a> the obligation to close is to share that obligation, so that only when the last shared reference is destructed does the object get closed. <\/p>\n<pre>\ntemplate&lt;typename T&gt;\nclass ensure_close\n{\npublic:\n  ensure_close(T^ t) : m_t(t) { }\n  ~ensure_close() { delete m_t; }\n\n  \/\/ Disallow copying and moving\n  ensure_close(const ensure_close&amp; other) = delete;\n  ensure_close&amp; operator=(const ensure_close&amp; other) = delete;\n  ensure_close(const ensure_close&amp;&amp; other) = delete;\n  ensure_close&amp; operator=(const ensure_close&amp;&amp; other) = delete;\n\nprivate:\n  T^ m_t;\n};\n\ntemplate&lt;typename T&gt;\nusing shared_close = std::shared_ptr&lt;ensure_close&lt;T&gt;&gt;;\n\ntemplate&lt;typename T&gt;\nauto make_shared_close(T^ t)\n{\n  return std::make_shared&lt;ensure_close&lt;T&gt;&gt;(t);\n}\n<\/pre>\n<p>Now you can copy the <code>shared_close<\/code> around, and only when the last copy is destructed does the wrapped hat pointer get closed.&sup1; <\/p>\n<pre>\nvoid Scenario1_Render::ViewPage()\n{\n    ...\n\n    if (outfile)\n    {\n        auto page = pdfDocument-&gt;GetPage(pageIndex);\n        <font COLOR=\"blue\">auto usingPage = make_shared_close(page);<\/font>\n\n        return create_task(outfile-&gt;OpenTransactedWriteAsync())\n            .then([this, page, <font COLOR=\"blue\">usingPage<\/font>]\n                  (StorageStreamTransaction^ transaction)\n        {\n            <font COLOR=\"blue\">auto usingTransaction = make_shared_close(transaction);<\/font>\n            auto options = ref new PdfPageRenderOptions();\n            options-&gt;DestinationHeight = (unsigned)(page-&gt;Size.Height * 2);\n            options-&gt;DestinationWidth = (unsigned)(page-&gt;Size.Width * 2);\n            return create_task(page-&gt;RenderToStreamAsync(transaction-&gt;Stream, options))\n                .then([this, <font COLOR=\"blue\">usingPage, usingTransaction<\/font>]()\n            {\n                <font COLOR=\"blue\">\/\/ destruction of the last shared usingPage\n                \/\/ and usingTransaction will close the page and transaction.<\/font>\n            });\n        });\n    }\n    ...\n}\n<\/pre>\n<p>Still, you have to remember to keep passing the <code>usingPage<\/code> and <code>usingTransaction<\/code> around. If you forget, then the object gets closed prematurely. (And if the <code>shared_close<\/code> is created by one lambda and consumed by a sibling lambda, well you now have <a HREF=\"https:\/\/en.wikipedia.org\/wiki\/David_Wheeler_(British_computer_scientist)#Quotes\">a <code>shared_ptr<\/code> to a <code>shared_close<\/code><\/a>, which is getting ridiculous.) <\/p>\n<p>But wait, you can stop the madness. <\/p>\n<p>Let&#8217;s go back to <code>unique_close<\/code>: This class becomes much more convenient if you use the <code>co_await<\/code> keyword, because the compiler will do the heavy lifting of cleaning up when the last task has completed.&sup2; <\/p>\n<pre>\ntask&lt;void&gt; Scenario1_Render::ViewPageAsync()\n{\n    ...\n\n    if (outfile)\n    {\n        auto page = pdfDocument-&gt;GetPage(pageIndex);\n        <font COLOR=\"blue\">auto usingPage = make_unique_close(page);<\/font>\n\n        auto transaction =\n            co_await outfile-&gt;OpenTransactedWriteAsync();\n        <font COLOR=\"blue\">auto usingTransaction = make_unique_close(transaction);<\/font>\n        auto options = ref new PdfPageRenderOptions();\n        options-&gt;DestinationHeight = (unsigned)(page-&gt;Size.Height * 2);\n        options-&gt;DestinationWidth = (unsigned)(page-&gt;Size.Width * 2);\n        co_await page-&gt;RenderToStreamAsync(transaction-&gt;Stream, options);\n        <font COLOR=\"blue\">\/\/ destruction of usingPage and usingTransaction\n        \/\/ will close the page and transaction.<\/font>\n    }\n    ...\n}\n<\/pre>\n<p>We have offloaded all the thinking to the compiler. The compiler will do the work of making sure that the <code>unique_close<\/code> objects are destructed when control leaves the block. The <code>unique_close<\/code> objects will remain alive during the <code>co_await<\/code> statements, which is what we want. <\/p>\n<p>We could make our <code>unique_close<\/code> a little fancier by making it a little more <code>unique_ptr<\/code>y. <\/p>\n<pre>\ntemplate&lt;typename T&gt;\nclass unique_close\n{\npublic:\n  unique_close(T^ t) : m_t(t) { }\n  ~unique_close() { delete m_t; }\n\n  <font COLOR=\"blue\">T^ get() { return m_t; }\n  T^ operator*() { return m_t; }\n  T^ operator-&gt;() { return m_t; }<\/font>\n  ...\n};\n<\/pre>\n<p>This leaves us with <\/p>\n<pre>\ntask&lt;void&gt; Scenario1_Render::ViewPageAsync()\n{\n    ...\n\n    if (outfile)\n    {\n        auto page = <font COLOR=\"blue\">make_unique_close(<\/font>\n             pdfDocument-&gt;GetPage(pageIndex)<font COLOR=\"blue\">)<\/font>;\n        auto transaction = <font COLOR=\"blue\">make_unique_close(<\/font>\n            co_await outfile-&gt;OpenTransactedWriteAsync()<font COLOR=\"blue\">)<\/font>;\n        auto options = ref new PdfPageRenderOptions();\n        options-&gt;DestinationHeight = (unsigned)(page-&gt;Size.Height * 2);\n        options-&gt;DestinationWidth = (unsigned)(page-&gt;Size.Width * 2);\n        co_await page-&gt;RenderToStreamAsync(transaction-&gt;Stream, options);\n        <font COLOR=\"blue\">\/\/ destruction of page and transaction\n        \/\/ will close the page and transaction.<\/font>\n    }\n    ...\n}\n<\/pre>\n<p>That doesn&#8217;t seem so bad. Pretty close to C# but still in the spirit of C++.&sup3; <\/p>\n<p>&sup1; You (and by &#8220;you&#8221; I mean &#8220;me&#8221;) would be sorely tempted to write this with a custom deleter instead. <\/p>\n<pre>\nnamespace Details\n{\n  template&lt;typename T&gt;\n  struct close_deleter\n  {\n    void operator()(T^ t) { delete t; }\n  };\n}\n\ntemplate&lt;typename T&gt;\nauto make_shared_close(T^ t)\n{\n    return std::shared_ptr&lt;T&gt;(t, Details::close_deleter&lt;T&gt;());\n}\n<\/pre>\n<p>Except that this doesn&#8217;t work because <code>std::shared_ptr<\/code> manages raw pointers, not hat pointers. <\/p>\n<p>&sup2; If you are a total crazy person, you might consider adding a boolean conversion operator to the <code>unique_close<\/code>: <\/p>\n<pre>\n...\n   operator bool() const { return true; }\n...\n<\/pre>\n<p>This appears to serve no purpose, but it lets you write this: <\/p>\n<pre>\n\/\/ Oh my goodness what kind of craziness is about to happen?\n#define scope_using__(t, c) \\\n    if (auto _scope_using_##c##_ = make_unique_close(t))\n#define scope_using_(t, c) scope_using__(t, c) \n#define scope_using(t) scope_using(t, __COUNTER__)\n\ntask&lt;void&gt; Scenario1_Render::ViewPageAsync()\n{\n    ...\n\n    if (outfile)\n    {\n        auto page = pdfDocument-&gt;GetPage(pageIndex);\n        <font COLOR=\"blue\">scope_using (page)\n        {<\/font>\n            auto transaction =\n                co_await outfile-&gt;OpenTransactedWriteAsync();\n            <font COLOR=\"blue\">scope_using (transaction)\n            {<\/font>\n                auto options = ref new PdfPageRenderOptions();\n                options-&gt;DestinationHeight = (unsigned)(page-&gt;Size.Height * 2);\n                        options-&gt;DestinationWidth = (unsigned)(page-&gt;Size.Width * 2);\n                co_await page-&gt;RenderToStreamAsync(transaction-&gt;Stream, options);\n                <font COLOR=\"blue\">\/\/ exiting the scope_using will close\n                \/\/ the corresponding objcts.<\/font>\n            }\n        }\n    }\n    ...\n}\n<\/pre>\n<p>This is a moral outrage. <a HREF=\"http:\/\/tvtropes.org\/pmwiki\/pmwiki.php\/Main\/LetUsNeverSpeakOfThisAgain\">Let us never speak of this again<\/a>. <\/p>\n<p>&sup3; If you wanted to be cute, you could rename <code>make_unique_close<\/code> to <code>Using<\/code>. <\/p>\n<pre>\nauto page = <font COLOR=\"blue\">Using<\/font>(pdfDocument-&gt;GetPage(pageIndex));\nauto transaction = <font COLOR=\"blue\">Using<\/font>(co_await outfile-&gt;OpenTransactedWriteAsync());\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>The co_await enables new patterns.<\/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-96515","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>The co_await enables new patterns.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/96515","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=96515"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/96515\/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=96515"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=96515"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=96515"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}