{"id":108329,"date":"2023-06-12T07:00:00","date_gmt":"2023-06-12T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=108329"},"modified":"2023-06-12T06:49:17","modified_gmt":"2023-06-12T13:49:17","slug":"20230612-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20230612-00\/?p=108329","title":{"rendered":"The move constructor that you have to declare, even though you don&#8217;t want anyone to actually call it"},"content":{"rendered":"<p>Blah blah blah C++ return value optimization (RVO), named return value optimization (NRVO), and copy elision.<\/p>\n<p>RVO support was optional in C++11 but became mandatory in C++17. NRVO support remains optional (but recommended).<\/p>\n<p>To allow NRVO in C++17 (or RVO and NRVO in C++11), a move constructor must be available, even though the compiler will not call it if the optimization is employed.<\/p>\n<p>You may have a class that you want to participate in RVO or NRVO, but you also don&#8217;t want it to be moved. For example, it may contain a <code>std::mutex<\/code>, which is not movable. But you nevertheless have to declare a move constructor. What can you do?<\/p>\n<p>Declare the move constructor, but don&#8217;t implement it.<\/p>\n<pre>class MyClass\r\n{\r\npublic:\r\n  MyClass();\r\n\r\n  \/\/ Not copyable.\r\n  MyClass(const MyClass&amp;) = delete;\r\n\r\n  \/\/ Movable only for NRVO purposes (and RVO in C++11).\r\n  \/\/ Never implemented.\r\n  MyClass(MyClass&amp;&amp;);\r\n\r\n  \/\/ Not assignable.\r\n  void operator=(const MyClass&amp;) = delete;\r\n};\r\n\r\nMyClass test1()\r\n{\r\n    return MyClass(); \/\/ RVO\r\n}\r\n\r\nMyClass test2()\r\n{\r\n    MyClass c;\r\n    return c; \/\/ NRVO\r\n}\r\n\r\nMyClass test3()\r\n{\r\n    MyClass c, d;\r\n    if (some_condition()) {\r\n        return c; \/\/ failed NRVO\r\n    } else {\r\n        return d; \/\/ failed NRVO\r\n    }\r\n}\r\n<\/pre>\n<p>We declared a move constructor in order to permit RVO in C++11 and NRVO everywhere. The compiler demands to see a move constructor, even though RVO and NRVO ultimately optimize it out.<\/p>\n<p>The first test shows that RVO works. The second test shows that NRVO works.<\/p>\n<p>The <code>test3<\/code> version compiles but does not link: NRVO is not possible given the way that <code>test3<\/code> is written, and the compiler is forced to use the move constructor to move either <code>c<\/code> or <code>d<\/code> into the return value. We declared the move constructor but never implemented it, so we get an unresolved external, which tells us, &#8220;Sorry, this object doesn&#8217;t support move, even though the tin says that it does. The label on the tin is a lie and exists only to allow the compiler to use RVO and NRVO.&#8221;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Forcing named return value optimization.<\/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-108329","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Forcing named return value optimization.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/108329","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=108329"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/108329\/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=108329"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=108329"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=108329"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}