{"id":103780,"date":"2020-05-22T07:00:00","date_gmt":"2020-05-22T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=103780"},"modified":"2020-07-02T06:54:55","modified_gmt":"2020-07-02T13:54:55","slug":"20200522-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200522-00\/?p=103780","title":{"rendered":"On the various ways of constructing a C++\/WinRT com_array"},"content":{"rendered":"<p>The C++\/WinRT <code>com_array&lt;T&gt;<\/code> represents a C-style conformant array of data where the underlying buffer is allocated via the COM task allocator. It is typically used to represent a C-style conformant array which is allocated by one component and freed by another.<\/p>\n<p>You will probably need to make one of these things when you are returning a projected array to the caller, either as the return value or through an output parameter. Here are <a href=\"https:\/\/github.com\/microsoft\/cppwinrt\/blob\/6f1c52ca12e05d71b0c95e03e5dd4e08dd60b56d\/strings\/base_array.h#L227\"> your choices of constructor<\/a>, with names that I made up.<\/p>\n<p><!-- ... BORDER=1 RULES=rows ... doesn't work because of site style sheet, must remove border and add to each row manually; also, WP doesn't like \"FONT SIZE\" --><\/p>\n<table style=\"border-collapse: collapse;\" border=\"0\" rules=\"rows\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr style=\"border: solid #cccccc; border-width: 1px 0;\">\n<td><tt>com_array();<\/tt><\/td>\n<td valign=\"middle\"><span style=\"font-size: 80%;\">(1)<\/span><\/td>\n<\/tr>\n<tr style=\"border: solid #cccccc; border-width: 1px 0;\">\n<td><tt>com_array(uint32_t count);<\/tt><\/td>\n<td valign=\"middle\"><span style=\"font-size: 80%;\">(2)<\/span><\/td>\n<\/tr>\n<tr style=\"border: solid #cccccc; border-width: 1px 0;\">\n<td><tt>com_array(uint32_t count, T const&amp; value);<\/tt><\/td>\n<td valign=\"middle\"><span style=\"font-size: 80%;\">(3)<\/span><\/td>\n<\/tr>\n<tr style=\"border: solid #cccccc; border-width: 1px 0;\">\n<td><tt>template&lt;typename InIt&gt;<br \/>\ncom_array(InIt first, InIt last)<\/tt><\/td>\n<td valign=\"middle\"><span style=\"font-size: 80%;\">(4)<\/span><\/td>\n<\/tr>\n<tr style=\"border: solid #cccccc; border-width: 1px 0;\">\n<td><tt>com_array(std::vector&lt;T&gt; const&amp; value)<\/tt><\/td>\n<td valign=\"middle\"><span style=\"font-size: 80%;\">(5)<\/span><\/td>\n<\/tr>\n<tr style=\"border: solid #cccccc; border-width: 1px 0;\">\n<td><tt>template&lt;size_t N&gt;<br \/>\ncom_array(std::array&lt;T, N&gt; const&amp; value)<\/tt><\/td>\n<td valign=\"middle\"><span style=\"font-size: 80%;\">(6)<\/span><\/td>\n<\/tr>\n<tr style=\"border: solid #cccccc; border-width: 1px 0;\">\n<td><tt>template&lt;size_t N&gt;<br \/>\ncom_array(T const(&amp;value)[N])<\/tt><\/td>\n<td valign=\"middle\"><span style=\"font-size: 80%;\">(7)<\/span><\/td>\n<\/tr>\n<tr style=\"border: solid #cccccc; border-width: 1px 0;\">\n<td><tt>com_array(std::initializer_list&lt;T&gt; value)<\/tt><\/td>\n<td valign=\"middle\"><span style=\"font-size: 80%;\">(8)<\/span><\/td>\n<\/tr>\n<tr style=\"border: solid #cccccc; border-width: 1px 0;\">\n<td><tt>com_array(void* ptr, uint32_t count,<br \/>\n\u00a0\u00a0take_ownership_from_abi_t);<\/tt><\/td>\n<td valign=\"middle\"><span style=\"font-size: 80%;\">(9)<\/span><\/td>\n<\/tr>\n<tr style=\"border: solid #cccccc; border-width: 1px 0;\">\n<td><tt>com_array(com_array&amp;&amp; other)<\/tt><\/td>\n<td valign=\"middle\"><span style=\"font-size: 80%;\">(10)<\/span><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><span style=\"font-size: 80%;\">1)<\/span> Default constructor: Creates an empty buffer.<\/p>\n<p><span style=\"font-size: 80%;\">2)<\/span> Capacity constructor (default value): Creates a buffer of <code>count<\/code> elements, all containing copies of a default-constructed <code>T<\/code>.<\/p>\n<p><span style=\"font-size: 80%;\">3)<\/span> Capacity constructor (explicit value): Creates a buffer of <code>count<\/code> elements, each of which is a copy of the provided value.<\/p>\n<p><span style=\"font-size: 80%;\">4)<\/span> Range constructor: Creates a buffer that is a copy of the range <code>[first, last)<\/code>.<\/p>\n<p><span style=\"font-size: 80%;\">5)<\/span> Vector constructor: Creates a buffer that is a copy of the contents of the vector.<\/p>\n<p><span style=\"font-size: 80%;\">6)<\/span> Array constructor: Creates a buffer that is a copy of the contents of the array.<\/p>\n<p><span style=\"font-size: 80%;\">7)<\/span> C-style array constructor: Creates a buffer that is a copy of the contents of the C-style array.<\/p>\n<p><span style=\"font-size: 80%;\">8)<\/span> Initializer-list constructor: Creates a buffer that is a copy of the contents of the initializer list.<\/p>\n<p><span style=\"font-size: 80%;\">9)<\/span> ABI constructor: Takes ownership of a buffer of specified length.<\/p>\n<p><span style=\"font-size: 80%;\">10)<\/span> Move constructor: Moves the resources from another <code>com_array<\/code> of the same type, leaving the original empty.<\/p>\n<p><b>Remarks for capacity constructor with default value <span style=\"font-size: 80%;\">(2)<\/span><\/b><\/p>\n<div style=\"margin-left: 1em;\">\n<p>Constructor <span style=\"font-size: 80%;\">(2)<\/span> is almost but not quite the same as creating a buffer of <code>count<\/code> elements each of which is a default-constructed <code>T<\/code>. Consider:<\/p>\n<pre>auto players = com_array&lt;MediaPlayer&gt;(50);\r\n<\/pre>\n<p>The <code>MediaPlayer<\/code> object&#8217;s default constructor creates a reference to a new media player object, and its copy constructor copies the reference. Therefore, the above line of code creates an array of 50 references to the same media player object, not an array of 50 different media player objects.<\/p>\n<p><b>Bonus weirdness<\/b>: If you pass a <code>count<\/code> of zero, the <code>com_array<\/code> will still default-contruct a <code>T<\/code>, even though it doesn&#8217;t use it for anything.<\/p>\n<\/div>\n<p><b>Remarks for capacity constructor with explicit value <span style=\"font-size: 80%;\">(3)<\/span><\/b><\/p>\n<div style=\"margin-left: 1em;\">\n<p><code>com_array(2, 42)<\/code> is interpreted as an attempt to use the range constructor <span style=\"font-size: 80%;\">(4)<\/span>, which fails because <code>2<\/code> and <code>42<\/code> are not iterators. To get this to be interpreted as a capacity constructor with explicit <code>int32_t<\/code> value, use an explicitly unsigned integer as the first parameter: <code>com_array(2u, 42)<\/code>.<\/p>\n<\/div>\n<p><b>Remarks for range constructor <span style=\"font-size: 80%;\">(4)<\/span><\/b><\/p>\n<div style=\"margin-left: 1em;\">\n<p>Sadly, there is (as of this writing)\u00b9 no deduction guide for the range constructor <span style=\"font-size: 80%;\">(4)<\/span>, so you will have to state the underlying type <code>T<\/code> explicitly:<\/p>\n<pre>auto a = com_array&lt;T&gt;(source.begin(), source.end());\r\n<\/pre>\n<p><b>Bonus trick<\/b>: If you want to move the range rather than copy it, use the <code>std::<\/code><code>move_<\/code><code>iterator<\/code> iterator adaptor:<\/p>\n<pre>auto a = com_array&lt;T&gt;(std::move_iterator(source.begin()),\r\n                      std::move_iterator(source.end()));\r\n<\/pre>\n<\/div>\n<p><b>Remarks for vector <span style=\"font-size: 80%;\">(5)<\/span>, array <span style=\"font-size: 80%;\">(6)<\/span>, and C-style array <span style=\"font-size: 80%;\">(7)<\/span> constructors<\/b><\/p>\n<div style=\"margin-left: 1em;\">\n<p>For constructors <span style=\"font-size: 80%;\">(5)<\/span> through <span style=\"font-size: 80%;\">(7)<\/span>, the contents of the container are copied. You can use the range constructor <span style=\"font-size: 80%;\">(4)<\/span> with the <code>move_<\/code><code>iterator<\/code> iterator adaptor to move the contents into the <code>com_<\/code><code>array<\/code> instead of copying.<\/p>\n<\/div>\n<p><b>Remarks for ABI constructor <span style=\"font-size: 80%;\">(9)<\/span><\/b><\/p>\n<div style=\"margin-left: 1em;\">\n<p>The ABI constructor <span style=\"font-size: 80%;\">(9)<\/span> is the lowest-level constructor. Use it when you have a block of memory already allocated via <code>Co\u00adTask\u00adMem\u00adAlloc<\/code> and you want the <code>com_array<\/code> to assume responsibility for it. To emphasize the special requirements for this constructor, the final parameter must be <code>take_<\/code><code>ownership_<\/code><code>from_<\/code><code>abi<\/code>.<\/p>\n<\/div>\n<p>\u00b9 Hint hint. Add a deduction guide and create a PR. While you&#8217;re at it, fix the range constructor so it doesn&#8217;t inadvertently trigger for <code>com_array(2, 42)<\/code>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Surveying the constructors.<\/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-103780","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Surveying the constructors.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103780","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=103780"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103780\/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=103780"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=103780"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=103780"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}