{"id":103463,"date":"2020-02-20T07:00:00","date_gmt":"2020-02-20T15:00:00","guid":{"rendered":"http:\/\/devblogs.microsoft.com\/oldnewthing\/?p=103463"},"modified":"2020-02-20T16:19:30","modified_gmt":"2020-02-21T00:19:30","slug":"20200220-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200220-00\/?p=103463","title":{"rendered":"If you&#8217;re not keeping the parameter, then you still want to have separate <CODE>T const&amp;<\/CODE> and <CODE>T&amp;&amp;<\/CODE> overloads"},"content":{"rendered":"<p>Last time, I noted that <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200219-00\/?p=103452\"> if you plan on keeping the parameter anyway, then there&#8217;s no need to have separate <code>T const&amp;<\/code> and <code>T&amp;&amp;<\/code> overloads<\/a>. However, the converse also applies: If you&#8217;re not keeping the parameter, then you still want to have separate <code>T const&amp;<\/code> and <code>T&amp;&amp;<\/code> overloads.<\/p>\n<p>To recap, we started with a class like this:<\/p>\n<pre>class Widget\r\n{\r\npublic:\r\n  <span style=\"color: blue;\">void SetValues(std::vector&lt;int&gt; const&amp; values)<\/span>\r\n  {\r\n    m_values = values;\r\n  }\r\n\r\n  <span style=\"color: blue;\">void SetValues(std::vector&lt;int&gt;&amp;&amp; values)<\/span>\r\n  {\r\n    m_values = std::move(values);\r\n  }\r\nprivate:\r\n  std::vector&lt;int&gt; m_values;\r\n};\r\n<\/pre>\n<p>We were able to simplify this to<\/p>\n<pre>class Widget\r\n{\r\npublic:\r\n  <span style=\"color: blue;\">void SetValues(std::vector&lt;int&gt; values)<\/span>\r\n  {\r\n    m_values = std::move(values);\r\n  }\r\n\r\nprivate:\r\n  std::vector&lt;int&gt; m_values;\r\n};\r\n<\/pre>\n<p>because we are going to keep the parameter either way. (The old way resulted in either a copy or a move. The new way produces either a copy+move or a move. The expectation is that a single move is relatively inexpensive.)<\/p>\n<p>However, the simplification doesn&#8217;t apply if we are not the ones consuming the value.<\/p>\n<pre>Widget CreateWidgetWithValues(std::vector&lt;int&gt; values)\r\n{\r\n  Widget widget;\r\n  widget.SetValues(std::move(values));\r\n  return widget;\r\n}\r\n<\/pre>\n<p>In this case, we are moving the <code>values<\/code> onward to the <code>SetValues<\/code> method, who is the final consumer. Writing the method this way generates an extra move constructor, because we have to move the value from our inbound parameter into the outbound parameter to <code>SetValues<\/code>. We also incur an extra destruction of our now-empty inbound parameter. If the parameter is passed through multiple layers, each layer adds an extra move constructor and destruction.<\/p>\n<p>Since we are not the final consumer, we should forward the parameter.<\/p>\n<pre>template&lt;typename Values&gt;\r\nWidget CreateWidgetWithValues(Values&amp;&amp; values)\r\n{\r\n  Widget widget;\r\n  widget.SetValues(std::forward&lt;Values&gt;(values));\r\n  return widget;\r\n}\r\n<\/pre>\n<p>Unfortunately, this causes us to break existing code, since you cannot forward uniform initialization.<\/p>\n<pre>\/\/ doesn't work any more\r\nCreateWidgetWithValues({ range.begin(), range.end() });\r\n<\/pre>\n<p>We end up returning to the overload.<\/p>\n<pre>Widget CreateWidgetWithValues(const std::vector&lt;int&gt;&amp; values)\r\n{\r\n  Widget widget;\r\n  widget.SetValues(values);\r\n  return widget;\r\n}\r\n\r\nWidget CreateWidgetWithValues(std::vector&lt;int&gt;&amp;&amp; values)\r\n{\r\n  Widget widget;\r\n  widget.SetValues(std::move(values));\r\n  return widget;\r\n}\r\n<\/pre>\n<p>I&#8217;m not too happy with this, though. Maybe there&#8217;s an easier way. Let me know.<\/p>\n<p><b>Bonus chatter<\/b>: The Microsoft compiler makes the function responsible for destructing its inbound parameters, in which case the code to destruct the <code>std::vector&lt;int&gt;<\/code> is part of the consuming function and is therefore shared. gcc and clang make it the caller&#8217;s responsibility, so the destruction of the parameter is repeated at each call site.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Forwarding it onward.<\/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-103463","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Forwarding it onward.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103463","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=103463"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103463\/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=103463"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=103463"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=103463"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}