{"id":105985,"date":"2021-11-30T07:00:00","date_gmt":"2021-11-30T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=105985"},"modified":"2021-11-30T07:29:06","modified_gmt":"2021-11-30T15:29:06","slug":"20211130-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20211130-00\/?p=105985","title":{"rendered":"How can my C++\/WinRT component pass a <CODE>std::vector<\/CODE> back to the caller?"},"content":{"rendered":"<p>The ReceiveArray pattern is the Windows Runtime pattern for how a function can return a C-style conformant array to its caller. In C++\/WinRT, the projected version of the function is<\/p>\n<pre>\/\/ [out] parameter\r\nvoid M(com_array&lt;T&gt;&amp; value);\r\n\r\n\/\/ return value\r\ncom_array&lt;T&gt; M();\r\n<\/pre>\n<p>A customer had a method that generated the result into a <code>std::vector&lt;int&gt;<\/code>. How do you return this to the caller? &#8220;There is no move constructor for <code>com_array&lt;int&gt;<\/code> that takes a <code>std::vector&lt;int&gt;<\/code>.&#8221;<\/p>\n<p>That&#8217;s right, there is no constructor for <code>com_array&lt;int&gt;<\/code> that takes a <code>std::vector&lt;int&gt;&amp;&amp;<\/code>. If you think about it, there can&#8217;t possibly be one.<\/p>\n<p>The <code>com_array<\/code> is required to use the COM task allocator to allocate its memory, because the memory is going to be passed back to the calling component, and the calling component is responsible for freeing the memory. This means that the memory allocator must be something language-agnostic, since the caller could be written in C# or Visual Basic or JavaScript or Rust or whatever.<\/p>\n<p>On the other hand, <code>std::vector<\/code> uses the C++ free store to allocate memory.\u00b9 This is an allocator specific to the C++ language. Actually, it&#8217;s even worse. It&#8217;s an allocator that is specific to a particular <i>implementation<\/i> of the C++ language. Code that uses one version of the compiler and runtime library cannot interoperate with code that uses a different version of the compiler and runtime library.<\/p>\n<p>The allocators don&#8217;t agree, so you won&#8217;t be able to transfer ownership: The memory was allocated from some version of the C++ free store, but putting it in a <code>com_array<\/code> will result in the memory being freed by <code>Co\u00adTask\u00adMem\u00adFree<\/code>.<\/p>\n<p>Okay, so you can&#8217;t move it into a <code>com_array<\/code>, but can you copy it?<\/p>\n<p>Yes, and the <code>com_array<\/code> even has a special constructor for copying from a <code>std::vector<\/code>.<\/p>\n<pre>\r\nstd::vector&lt;int32_t&gt; m_indices;\r\n\r\ncom_array&lt;int32_t&gt; GetIndices()\r\n{\r\n    return com_array&lt;int32_t&gt;(m_indices);\r\n}\r\n<\/pre>\n<p>Starting in C++\/WinRT version 2.0.200601.2, there&#8217;s a deduction guide that that deduces <code>com_array&lt;T&gt;<\/code> if you construct from a <code>std::vector&lt;T&gt;<\/code>, so you need only write<\/p>\n<pre>com_array&lt;int32_t&gt; GetIndices()\r\n{\r\n    return com_array(m_indices);\r\n}\r\n<\/pre>\n<p>If you aren&#8217;t wedded to <code>std::vector<\/code>, you could generate the results directly into a <code>winrt::com_array<\/code> and return it, thereby avoiding a copy.<\/p>\n<p>\u00b9 You can override this by providing a custom allocator, say, by a custom allocator that obtains memory via <code>Co\u00adTask\u00adMem\u00adAlloc<\/code>. However, library types with custom allocators are going to create interop friction with other code that expects library types with the standard allocator.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Implementing the ReceiveArray pattern.<\/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-105985","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Implementing the ReceiveArray pattern.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/105985","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=105985"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/105985\/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=105985"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=105985"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=105985"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}