{"id":27135,"date":"2020-11-20T15:49:10","date_gmt":"2020-11-20T15:49:10","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/cppblog\/?p=27135"},"modified":"2020-11-20T15:49:10","modified_gmt":"2020-11-20T15:49:10","slug":"conditionally-trivial-special-member-functions","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/cppblog\/conditionally-trivial-special-member-functions\/","title":{"rendered":"Conditionally Trivial Special Member Functions"},"content":{"rendered":"<p>The C++ standards committee is currently focusing on adding features to the language which can simplify code. One small example of this in C++20 is <a href=\"http:\/\/www.open-std.org\/jtc1\/sc22\/wg21\/docs\/papers\/2019\/p0848r3.html\">conditionally trivial special member functions<\/a>, which we added support for in <a href=\"https:\/\/docs.microsoft.com\/en-us\/visualstudio\/releases\/2019\/release-notes\">Visual Studio 2019 version 16.8<\/a>. Its benefit isn\u2019t immediately obvious unless you\u2019ve been deep down the rabbit hole of high-performance library authoring, so I\u2019ve written this post to show you how it can make certain generic types more efficient without requiring huge amounts of template magic.<\/p>\n<h2>The Problem<\/h2>\n<p>Types which wrap other types are common in the C++ world: pairs, tuples, optionals, adapters, etc. For some of these your implementation can\u2019t use the default special member functions (default constructor, copy\/move constructor, copy\/move assignment, destructor) because there\u2019s some additional work that needs to be done. Take for example this <code>std::optional<\/code>-like type:<code><\/code><\/p>\n<pre class=\"prettyprint\">template\u00a0&lt;typename\u00a0T&gt;\r\nstruct\u00a0optional\u00a0{\r\n\u00a0\u00a0\u00a0bool\u00a0has_value_;\r\n\u00a0\u00a0\u00a0union\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0T\u00a0value_;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0char empty_; \/\/dummy member\r\n\u00a0\u00a0\u00a0};\r\n};<\/pre>\n<p>It has a <code>bool<\/code> member to say whether it is currently storing a value, and a union member which either stores a value or stores a dummy member when the <code>optional<\/code> is empty.<\/p>\n<p>The default special members won\u2019t work here: when the union member has non-trivial constructors and destructors, we need to explicitly handle these in our <code>optional<\/code> type. Focusing on the copy constructor, here\u2019s a potential implementation:<\/p>\n<pre class=\"prettyprint\">\u00a0\u00a0\u00a0optional(optional\u00a0const&amp;\u00a0rhs)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0:\u00a0has_value_(rhs.has_value_),\u00a0empty_()\r\n\u00a0\u00a0\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0if\u00a0(has_value_)\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0new\u00a0(&amp;value_)\u00a0T(rhs.value_);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0}<\/pre>\n<p>We check if the <code>rhs<\/code> has a value, and if it does, we use it to copy-construct our own value.<\/p>\n<p>But there\u2019s a performance issue here. Say we make a copy of an <code>optional&lt;int&gt;<\/code>, like this:<\/p>\n<pre class=\"prettyprint\">optional&lt;int&gt; make_copy(optional&lt;int&gt; const&amp; o) {\r\n  return o;\r\n}<\/pre>\n<p>Since <code>int<\/code>s are <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/language\/copy_constructor#Trivial_copy_constructor\">trivially copy constructible<\/a> (i.e. one can copy them by copying their memory rather than having to use any constructors), copying the <code>optional&lt;int&gt;<\/code> <em>should<\/em> only require copying its byte representation. But this is the code which the compiler generates for <code>make_copy<\/code>:<\/p>\n<pre class=\"prettyprint\">      movzx eax, BYTE PTR [rdx]   #load o\r\n      mov BYTE PTR [rcx], al      #copy.has_value_ = rhs.has_value_\r\n      test al, al                 #test rhs.has_value_\r\n      je SHORT $EMPTY             #if it\u2019s empty, jump to the end\r\n      mov eax, DWORD PTR [rdx+4]  #load rhs.value_\r\n      mov DWORD PTR [rcx+4], eax  #store to copy.value_\r\n$EMPTY:\r\n      mov rax, rcx                #return copy\r\n      ret 0<\/pre>\n<p>What we really want is a way to use the default special member if the corresponding one in <code>T<\/code> is trivial, and otherwise use our custom one.<\/p>\n<h2>C++17 Approaches<\/h2>\n<p>One approach which at first seems possible is using <code><a href=\"https:\/\/en.cppreference.com\/w\/cpp\/types\/enable_if\">std::enable_if<\/a> <\/code>to select between the default and custom copy constructor implementations depending on the properties of <code>T<\/code>:<\/p>\n<pre class=\"prettyprint\">template &lt;class U = T, \r\n          std::enable_if_t&lt;std::is_copy_constructible_v&lt;U&gt; &amp;&amp; \r\n                           std::is_trivially_copy_constructible_v&lt;U&gt;&gt;* = nullptr&gt;\r\noptional(optional const&amp; rhs) = default;\r\n\r\ntemplate &lt;class U = T, \r\n          std::enable_if_t&lt;std::is_copy_constructible_v&lt;U&gt; &amp;&amp;\r\n                           !std::is_trivially_copy_constructible_v&lt;U&gt;&gt;* = nullptr&gt;\r\noptional(optional const&amp; rhs)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0: has_value_(rhs.has_value_), empty_()\r\n{\r\n\u00a0\u00a0\u00a0if (has_value_) {\r\n\u00a0\u00a0\u00a0new (&amp;value_) T(rhs.value_);\r\n\u00a0 }\r\n}<\/pre>\n<p>Unfortunately, special members other than the default constructor cannot be templates, so this doesn\u2019t work.<\/p>\n<p>The common solution which <em>does<\/em> work is to rip the storage and special members of the template into base classes and select which to inherit from by checking the relevant type traits. The implementation of this is fairly hairy, so I\u2019ve explained it down at the bottom of this post for those who want to see it.<\/p>\n<p>If we make this change, then the assembly for <code>make_copy<\/code> becomes this:<\/p>\n<pre class=\"prettyprint\">      mov rax, QWORD PTR [rdx]   #load o\r\n      mov QWORD PTR [rcx], rax   #copy memory\r\n      mov rax, rcx               #return copy\r\n      ret 0<\/pre>\n<p>Now we have more efficient code generated, but a whole load of tricky C++ which is hard to write, to maintain, and for the compiler to build efficiently. C++20 lets us keep the efficient assembly, and vastly simplifies the C++.<\/p>\n<h2>C++20 Solution<\/h2>\n<p>Although our<code> std::enable_if<\/code> solution from above wouldn\u2019t work because those functions can\u2019t be templates, you <em>can<\/em> constrain non-template functions using C++20 concepts:<\/p>\n<pre class=\"prettyprint\">optional(optional const&amp;) = default;\r\n\r\noptional(optional const&amp; rhs)\r\nrequires std::copy_constructible&lt;T&gt; &amp;&amp; !std::is_trivially_copy_constructible_v&lt;T&gt;\r\n\u00a0\u00a0\u00a0\u00a0: has_value_(rhs.has_value_), empty_()\r\n{\r\n\u00a0\u00a0\u00a0if (has_value_) {\r\n\u00a0\u00a0\u00a0new (&amp;value_) T(rhs.value_);\r\n\u00a0 }\r\n}<\/pre>\n<p>Now <code>optional&lt;T&gt;<\/code> is trivially copy constructible if and only if <code>T<\/code> is, with minimal template magic. We\u2019ve got both efficient code generation and C++ which can be understood and maintained a lot easier than before.<\/p>\n<h2>The Hairy C++17 Implementation<\/h2>\n<p>As promised, here\u2019s how you\u2019d do this in C++17.<\/p>\n<p>We start off by tearing the storage out into its own base class:<\/p>\n<pre class=\"prettyprint\">template\u00a0&lt;class\u00a0T&gt;\r\nstruct\u00a0optional_storage_base\u00a0{\r\n\u00a0\u00a0\u00a0optional_storage_base()\u00a0:\r\n\u00a0\u00a0\u00a0\u00a0\u00a0has_value_(false),\u00a0empty_()\r\n\u00a0\u00a0\u00a0{}\r\n\u00a0\u00a0\u00a0bool\u00a0has_value_;\r\n\u00a0\u00a0\u00a0union\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0T\u00a0value_;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0char empty_;\r\n\u00a0\u00a0\u00a0};\r\n};<\/pre>\n<p>We then have a base class for the copy constructor for when <code>T<\/code> is trivially copy constructible, and we introduce a default template parameter which we\u2019ll specialize later.<\/p>\n<pre class=\"prettyprint\">template\u00a0&lt;class\u00a0T,\u00a0bool\u00a0=\u00a0std::is_trivially_copy_constructible_v&lt;T&gt;&gt;\r\nstruct\u00a0optional_copy_base\u00a0:\u00a0optional_storage_base&lt;T&gt;\u00a0{\r\n  \/\/default copy ctor\r\n\u00a0\u00a0\u00a0optional_copy_base(optional_copy_base\u00a0const&amp;)\u00a0=\u00a0default;\r\n\r\n  \/\/have to default other special members\r\n\u00a0\u00a0\u00a0~optional_copy_base()\u00a0=\u00a0default;\r\n\u00a0\u00a0\u00a0optional_copy_base()\u00a0=\u00a0default;\r\n\u00a0\u00a0\u00a0optional_copy_base(optional_copy_base&amp;&amp;)\u00a0=\u00a0default;\r\n\u00a0\u00a0\u00a0optional_copy_base&amp;\u00a0operator=(optional_copy_base\u00a0const&amp;)\u00a0=\u00a0default;\r\n\u00a0\u00a0\u00a0optional_copy_base&amp;\u00a0operator=(optional_copy_base\u00a0&amp;&amp;)\u00a0=\u00a0default;\r\n};<\/pre>\n<p>Then we specialize this template for when <code>T<\/code> is <em>not<\/em> trivially copy constructible:<\/p>\n<pre class=\"prettyprint\">template\u00a0&lt;class\u00a0T&gt;\r\nstruct\u00a0optional_copy_base&lt;T,\u00a0false&gt;\u00a0:\u00a0optional_storage_base&lt;T&gt;\u00a0{\r\n\u00a0\u00a0\u00a0optional_copy_base(optional_copy_base\u00a0const&amp;\u00a0rhs)\r\n\u00a0\u00a0\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0if\u00a0(rhs.has_value_)\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0this-&gt;has_value_\u00a0=\u00a0true;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0new\u00a0(&amp;this-&gt;value_)\u00a0T(rhs.value_);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0}\r\n\r\n\u00a0\u00a0\u00a0\/\/have\u00a0to\u00a0default\u00a0other\u00a0special\u00a0members\r\n\u00a0\u00a0\u00a0~optional_copy_base()\u00a0=\u00a0default;\r\n\u00a0\u00a0\u00a0optional_copy_base()\u00a0=\u00a0default;\r\n\u00a0\u00a0\u00a0optional_copy_base(optional_copy_base&amp;&amp;)\u00a0=\u00a0default;\r\n\u00a0\u00a0\u00a0optional_copy_base&amp;\u00a0operator=(optional_copy_base\u00a0const&amp;)\u00a0=\u00a0default;\r\n\u00a0\u00a0\u00a0optional_copy_base&amp;\u00a0operator=(optional_copy_base\u00a0&amp;&amp;)\u00a0=\u00a0default;\r\n};<\/pre>\n<p>Then we make optional inherit from<code> optional_copy_base&lt;T&gt;<\/code>:<\/p>\n<pre class=\"prettyprint\">template\u00a0&lt;typename\u00a0T&gt;\r\nstruct\u00a0optional\u00a0:\u00a0optional_copy_base&lt;T&gt;\u00a0{\r\n\u00a0\u00a0\u00a0\/\/other\u00a0members\r\n};<\/pre>\n<p>Then we do this all over again for the move constructor, destructor, copy assignment, and move assignment operators. This is exactly what <a href=\"https:\/\/github.com\/microsoft\/STL\/blob\/master\/stl\/inc\/optional\">standard library implementors have to go through<\/a> to get the best codegen possible at the expense of implementation and maintenance burden. It\u2019s not fun, trust me.<\/p>\n<h2>Give us your feedback<\/h2>\n<p>Download\u00a0<a href=\"https:\/\/visualstudio.microsoft.com\/vs\/\" target=\"_blank\" rel=\"noopener noreferrer\">Visual Studio 2019 version 16.8\u00a0<\/a>today and give it a try. We\u2019d love to hear from you to help us prioritize and build the right features for you. We can be reached via the comments below,\u00a0<a href=\"https:\/\/developercommunity.visualstudio.com\/spaces\/8\/index.html\" target=\"_blank\" rel=\"noopener noreferrer\">Developer Community<\/a>,\u00a0and Twitter (<a href=\"https:\/\/twitter.com\/visualc\" target=\"_blank\" rel=\"noopener noreferrer\">@VisualC<\/a>). The best way to file a bug or suggest a feature is via Developer Community.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The C++ standards committee is currently focusing on adding features to the language which can simplify code. One small example of this in C++20 is conditionally trivial special member functions, which we added support for in Visual Studio 2019 version 16.8. Its benefit isn\u2019t immediately obvious unless you\u2019ve been deep down the rabbit hole of [&hellip;]<\/p>\n","protected":false},"author":706,"featured_media":35994,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1,512],"tags":[],"class_list":["post-27135","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-cplusplus","category-general-cpp-series"],"acf":[],"blog_post_summary":"<p>The C++ standards committee is currently focusing on adding features to the language which can simplify code. One small example of this in C++20 is conditionally trivial special member functions, which we added support for in Visual Studio 2019 version 16.8. Its benefit isn\u2019t immediately obvious unless you\u2019ve been deep down the rabbit hole of [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts\/27135","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/users\/706"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/comments?post=27135"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts\/27135\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/media\/35994"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/media?parent=27135"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/categories?post=27135"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/tags?post=27135"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}