{"id":109503,"date":"2024-03-08T07:00:00","date_gmt":"2024-03-08T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=109503"},"modified":"2024-03-11T10:14:55","modified_gmt":"2024-03-11T17:14:55","slug":"20240308-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20240308-00\/?p=109503","title":{"rendered":"How can I force a copy of a C++ value?"},"content":{"rendered":"<p>Last time, we saw a case where <a title=\"In C++\/WinRT, you shouldn\u2019t destroy an object while you're co_awaiting it\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20240307-00\/?p=109490\"> we wanted to pass a copy of an object to an operator that accepted objects by reference<\/a>. We solved this by forcing a copy and using the copy.<\/p>\n<pre>\/\/ Original\r\nco_await m_pendingAction;\r\n\r\n\/\/ Alternative 1: Copy to a local\r\nauto pendingAction = m_pendingAction;\r\nco_await pendingAction;\r\n\r\n\/\/ Alternative 2: Copy to a temporary\r\nco_await winrt::IAsyncAction(m_pendingAction);\r\n<\/pre>\n<p>Our problem was motivated by the <code>co_await<\/code> operator, but this problem afflicts function calls, too.<\/p>\n<pre>void consume(Widget const&amp; widget, std::function&lt;void()&gt; callback);\r\n\r\nauto widget = std::make_unique&lt;Widget&gt;();\r\nconsume(*widget, [&amp;] {\r\n    widget.reset();\r\n});\r\n<\/pre>\n<p>In the above contrived example, we create a <code>widget<\/code> and pass it by reference to the <code>consume<\/code> method, but in the callback, we destroy the widget! You probably aren&#8217;t crazy enough to do this on purpose, but it might happen by accident due to reentrancy or a complex interaction between components. Again, the solution is to pass a copy.<\/p>\n<pre>\/\/ Pass a copy of the widget to consume in case the\r\n\/\/ original gets destroyed.\r\n\r\n\/\/ Alternative 1: Copy to a local\r\nauto widget_copy = *widget;\r\nconsume(widget_copy, [&amp;] {\r\n    widget.reset();\r\n});\r\n\r\n\/\/ Alternative 2: Copy to a temporary\r\nconsume(Widget(*widget), [&amp;] {\r\n    widget.reset();\r\n});\r\n<\/pre>\n<p>If only there were a convenient way to make a temporary copy of something. The first alternative requires you to name a local variable, and the lifetime of that local variable will extend to the of the block, which may be longer than you were expecting.<\/p>\n<p>The second alternative creates the temporary inline, but you have to spell out the type name, and that type name can get quite unwieldy.<\/p>\n<p>Maybe there&#8217;s a third way that gives us the inline temporary but also avoids typing out the type name. Here&#8217;s a start:<\/p>\n<pre>template&lt;typename T&gt;\r\nstd::decay_t&lt;T&gt; copy_of(T&amp;&amp; t)\r\n{ return std::forward&lt;T&gt;(t); }\r\n\r\nco_await copy_of(m_pendingAction);\r\n\r\nconsume(copy_of(*widget), [&amp;] {\r\n    widget.reset();\r\n});\r\n<\/pre>\n<p>The <code>copy_of<\/code> takes an arbitrary reference and returns a copy of whatever it refers to. There are some sneaky bits here.<\/p>\n<p>We can&#8217;t declare the parameter as <code>copy_of(T const&amp; t)<\/code> because <code>T<\/code> might not have a copy constructor from <code>T const&amp;<\/code>.<\/p>\n<p>We use <code>std::<wbr \/>decay_t<\/code> in case <code>T<\/code> has a cv-qualifier. (And to get rid of any reference declarators on <code>T<\/code> that may have been introduced by the forwarding reference.)<\/p>\n<p>Technically, the <code>std::forward&lt;T&gt;<\/code> is not necessary starting in C++17-maybe-20-question-mark?\u00b9 thanks to <a href=\"https:\/\/wg21.link\/p1825r0\"> P18250R0<\/a> which introduced implicit moves from rvalue reference parameters into return values. Basically, it says that if you <code>return<\/code> a parameter that is an rvalue reference, then the compiler is allowed to move from that parameter instead of its normal behavior of treating it as an lvalue. Nonetheless, it doesn&#8217;t hurt to be explicit about it, particularly if you aren&#8217;t confident that everyone will be using a C++17 compiler that incorporates P18250R0, or if you want your code to work downlevel to C++11.<\/p>\n<p>There&#8217;s also a problem if <code>T<\/code>&#8216;s copy constructor or move copy constructor is explicit. We&#8217;ll have to use an explicit conversion.<\/p>\n<p>And I forgot to put a <code>constexpr<\/code> on the function, so it can be compile-time evaluated; and I forgot to put a <code>noexcept<\/code> clause, which probably should follow <a title=\"Please repeat yourself: The noexcept(noexcept(...)) idiom\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20220408-00\/?p=106438\"> the <code>noexcept(noexcept)<\/code> idiom<\/a>, leaving us with<\/p>\n<pre>template&lt;typename T&gt;\r\nstd::decay_t&lt;T&gt; copy_of(T&amp;&amp; t)\r\nnoexcept(noexcept(\r\n    std::decay_t&lt;T&gt;(std::forward&lt;T&gt;(t))\r\n    ))\r\n{ return\r\n    std::decay_t&lt;T&gt;(std::forward&lt;T&gt;(t))\r\n; } \r\n<\/pre>\n<p>But wait, we&#8217;re not done yet.<\/p>\n<p>In <a href=\"https:\/\/www.open-std.org\/jtc1\/sc22\/wg21\/docs\/papers\/2021\/p0849r8.html\"> P0849R8<\/a>, C++23 added &#8220;<code>auto<\/code> decay copy&#8221; as a core language feature, so starting in C++23, you can write <code>auto(x)<\/code> to make a copy of <code>x<\/code>, removing the need for the <code>copy_of<\/code> function entirely.<\/p>\n<pre>\/\/ Await a copy because Cancel()\r\n\/\/ can modify it while awaiting.\r\nco_await auto(m_pendingAction);\r\n\r\n\/\/ Consume a copy because the lambda modifies it\r\n\/\/ from the callback.\r\nconsume(auto(*widget), [&amp;] {\r\n    widget.reset();\r\n});\r\n<\/pre>\n<p>It took over a decade, but we finally got there.<\/p>\n<p>\u00b9 P1825R0 was submitted as a C++17 defect report, which makes it retroactive to C++17, but it naturally takes time for compilers to implement the required changes, so the confidence level doesn&#8217;t really kick in until C++20.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Forcing a copy with a minimum of typing.<\/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-109503","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Forcing a copy with a minimum of typing.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109503","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=109503"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109503\/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=109503"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=109503"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=109503"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}