{"id":104181,"date":"2020-09-07T07:00:00","date_gmt":"2020-09-07T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=104181"},"modified":"2020-09-09T06:08:52","modified_gmt":"2020-09-09T13:08:52","slug":"20200907-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200907-00\/?p=104181","title":{"rendered":"C++\/WinRT injects additional constructors into each runtime class"},"content":{"rendered":"<p>C++\/WinRT treats runtime classes similar to C# reference types. Copying a C++\/WinRT runtime class copies a reference to the underlying object. You can null out the reference by assigning <code>nullptr<\/code> to it.<\/p>\n<p>On the other hand, C++ constructors don&#8217;t use the <code>new<\/code> keyword; the <code>new<\/code> keyword has a different meaning which doesn&#8217;t apply to Windows Runtime classes.<\/p>\n<p>This means that C++ constructors have to do double-duty: They can be used to construct new objects, or they can be used as copy constructors or conversion constructors.<\/p>\n<p>Constructors that actually, y&#8217;know, create new objects are represented as traditional C++ constructors.<\/p>\n<p>C++\/WinRT also injects additional constructors into each runtime class. One is the copy constructor, and another is the conversion constructor from <code>nullptr<\/code>.<\/p>\n<p>If you had a class that has a default constructor, or could construct from an integer, you would write it something like this:<\/p>\n<pre>class Thing\r\n{\r\npublic:\r\n    Thing();\r\n    explicit Thing(int capacity);\r\n};\r\n<\/pre>\n<p>The C++\/WinRT version looks similar, but with additional constructors:<\/p>\n<pre>class Thing\r\n{\r\npublic:\r\n    Thing();\r\n    explicit Thing(int capacity);\r\n    <span style=\"color: blue;\">Thing(std::nullptr_t);\r\n    Thing(Thing const&amp;) = default;\r\n    Thing(const&amp;&amp;) = default;<\/span>\r\n};\r\n<\/pre>\n<p>(If you look at the C++\/WinRT headers, you won&#8217;t see the default constructors. They simply are generated automatically by the compiler.)<\/p>\n<p>The first injected constructor is the conversion constructor from <code>nullptr<\/code>. The second and third are the copy and move copy constructors, which copy or move the reference to the underlying object.<\/p>\n<pre>\/\/ default constructor, creates an object\r\nThing t1;\r\n\r\n\/\/ explicit constructor, creates an object\r\nThing t2{ 42 }; \r\n\r\n\/\/ conversion from nullptr, creates an empty reference\r\nThing t3{ nullptr };\r\nThing t4 = nullptr;\r\n\r\n\/\/ copy constructor, copies reference to object\r\nThing t5{ t1 };\r\nThing t6 = t1;\r\n\r\n\/\/ move copy constructor, moves reference to object\r\nThing t5{ std::move(t1) };\r\nThing t6 = std::move(t1);\r\n<\/pre>\n<p>This conflation of reference construction and object construction can be confusing. For example, you might forget that the default constructor creates an object:<\/p>\n<pre>class Something\r\n{\r\nprivate:\r\n    Thing m_thing;\r\n};\r\n<\/pre>\n<p>This constructs a brand new <code>Thing<\/code> object when the <code>Something<\/code> constructs. If you wanted to start with an empty reference, you need to initialize <code>m_thing<\/code> with <code>nullptr<\/code>.<\/p>\n<pre>class Something\r\n{\r\nprivate:\r\n    Thing m_thing <span style=\"color: blue;\">= nullptr<\/span>;\r\n};\r\n<\/pre>\n<p>When designing your own runtime classes, you may want to avoid having a constructor whose single parameter is the same as the type being constructed, because that would conflict with the copy constructor.<\/p>\n<pre>runtimeclass Thing\r\n{\r\n  Thing(Thing parent);\r\n}\r\n<\/pre>\n<p>This would result in two conflicting projections into C++\/WinRT. Would<\/p>\n<pre>\/\/ assuming t1 is a Thing\r\nThing t2{ t1 };\r\n<\/pre>\n<p>be an attempt to construct a brand new <code>Thing<\/code>, using <code>t1<\/code> as the constructor parameter? Or would it be an attempt to copy the reference to the same underlying <code>Thing<\/code> object?<\/p>\n<p>You can work around this by using a static function that acts like a constructor.<\/p>\n<pre>runtimeclass Thing\r\n{\r\n  <span style=\"color: blue;\">static Thing CreateFromParent(Thing parent);<\/span>\r\n}\r\n<\/pre>\n<p>Or by changing it to a method on the parent.<\/p>\n<pre>runtimeclass Thing\r\n{\r\n  <span style=\"color: blue;\">Thing CreateChild();<\/span>\r\n}<\/pre>\n<p>There is also an ambiguity if you have a constructor that takes a single reference type, and it&#8217;s possible for that reference to be null.<\/p>\n<pre>runtimeclass ChildThing\r\n{\r\n  \/\/ parent=null means create parentless\r\n  ChildThing(ParentThing parent);\r\n}\r\n<\/pre>\n<p>In this case, you might be tempted to create a new parentless <code>ChildThing<\/code> object by saying this:<\/p>\n<pre>ChildThing child{ nullptr };\r\n<\/pre>\n<p>Unfortunately, this actually invokes the conversion constructor from <code>nullptr<\/code>. To construct a new parentless <code>ChildThing<\/code>, you need to write<\/p>\n<pre>ChildThing child{ ParentThing{ nullptr } };\r\n<\/pre>\n<p>A cleaner workaround is to provide a default constructor that creates a parentless <code>ChildThing<\/code>.<\/p>\n<pre>runtimeclass ChildThing\r\n{\r\n  <span style=\"color: blue;\">ChildThing(); \/\/ create parentless<\/span>\r\n  ChildThing(ParentThing parent); \/\/ creates with parent\r\n}\r\n<\/pre>\n<pre>\u00a0<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>For dealing with the objects as the smart pointers they actually are.<\/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-104181","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>For dealing with the objects as the smart pointers they actually are.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/104181","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=104181"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/104181\/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=104181"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=104181"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=104181"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}