{"id":105987,"date":"2021-12-01T07:00:00","date_gmt":"2021-12-01T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=105987"},"modified":"2021-11-30T07:32:11","modified_gmt":"2021-11-30T15:32:11","slug":"20211201-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20211201-00\/?p=105987","title":{"rendered":"How can I transfer ownership of a C-style array to a Windows Runtime component?"},"content":{"rendered":"<p>Suppose you have a large C-style array, and you want to transfer ownership of that array to a Windows Runtime component. For concreteness, let&#8217;s say that we have this:<\/p>\n<pre>namespace Sample\r\n{\r\n    runtimeclass Widget\r\n    {\r\n        \/\/ The \"indices\" array will be very large.\r\n        void SetIndices(Int32[] indices);\r\n    }\r\n}\r\n<\/pre>\n<p>You might be tempted to do something like this:<\/p>\n<pre>void SetWidgetIndices(Widget const&amp; widget)\r\n{\r\n  winrt::com_array&lt;int32_t&gt; indices = CalculateIndices();\r\n  widget.SetIndices(<span style=\"color: blue;\">std::move(indices)<\/span>);\r\n}\r\n<\/pre>\n<p>Using a <code>std::move<\/code> means that you are fine with the method stealing the resources out of the object, and you no-so-secretly hope that it will do so.<\/p>\n<p>But it won&#8217;t.<\/p>\n<p>If you look at the <a title=\"The various patterns for passing C-style arrays across the Windows Runtime ABI boundary\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200205-00\/?p=103398\"> rules for passing C-style arrays across the Windows Runtime ABI boundary<\/a>, you&#8217;ll see that a parameter declared as <code>T[] v<\/code> uses the <i>PassArray<\/i> pattern. In that pattern, ownership of the data remains with the caller, and the recipient must make a copy if it wants to access it beyond the end of the method.<\/p>\n<p>So that&#8217;s not going to work.<\/p>\n<p>The <i>FillArray<\/i> pattern doesn&#8217;t work either. That is for asking the method to fill a preallocated array, which is not what we&#8217;re doing here.<\/p>\n<p>And the last pattern, <i>ReceiveArray<\/i> doesn&#8217;t work, because that is for transferring ownership from the method back to the caller.<\/p>\n<p>So we&#8217;re stuck. How can we do this without incurring a copy of a large block of data?<\/p>\n<p>One option is to express the data in the form of an <code>IVector<\/code> instead of a C-style array. Since <code>IVector<\/code> is an interface, the recipient can just <code>AddRef<\/code> the interface and continue using it later. The major downside of this is that it costs you a lot of performance, since access to each element of an <code>IVector<\/code> is a virtual method call.\u00b9<\/p>\n<p>Another option is to express the data in the form of a byte buffer, <code>IBuffer<\/code>. However, this works only for types that have no destructor (like integers). Furthermore, getting the data into and out of the buffer is a bit awkward, since you have to do some casting of the byte buffer to get it into the form you want.<\/p>\n<pre>auto data = reinterpret_cast&lt;int32_t*&gt;(m_buffer.data());\r\nauto size = m_buffer.Length() \/ sizeof(int32_t);\r\nauto view = winrt::array_view(data, data + size);\r\n\/\/ access the data via the view\r\n<\/pre>\n<p>It&#8217;s also a problem for languages which do not have raw pointer types.<\/p>\n<p>It occurred to me that there&#8217;s still a third option, but you have to change your point of view: Since the only ownership-transferring operation is from the method to its caller, reverse the roles so that the caller can &#8220;return&#8221; the array to the method.<\/p>\n<pre>namespace Sample\r\n{\r\n    \/\/ The \"indices\" array will be very large.\r\n    <span style=\"color: blue;\">delegate Int32[] WidgetIndicesProducer();<\/span>\r\n\r\n    runtimeclass Widget\r\n    {\r\n        void SetIndices(<span style=\"color: blue;\">WidgetIndicesProducer producer<\/span>);\r\n    }\r\n}\r\n<\/pre>\n<p>To provide the indices, you actually provide a callback that generates the indices and returns them via the <i>ReceiveArray<\/i> pattern.<\/p>\n<pre>void SetWidgetIndices(Widget const&amp; widget)\r\n{\r\n  winrt::com_array&lt;int32_t&gt; indices = CalculateIndices();\r\n  widget.SetIndices(\r\n    <span style=\"color: blue;\">[&amp;] { return std::move(indices); }<\/span>);\r\n}\r\n<\/pre>\n<p>The <code>[&amp;]<\/code> capture assumes that the lambda will be called back before the <code>indices<\/code> variable is destructed. A safer version would be to store the indices inside the lambda itself.<\/p>\n<pre>void SetWidgetIndices(Widget const&amp; widget)\r\n{\r\n  widget.SetIndices(\r\n    <span style=\"color: blue;\">[indices = CalculateIndices()]() mutable<\/span>\r\n    { return std::move(indices); });\r\n}\r\n<\/pre>\n<p>You could simplify this to<\/p>\n<pre>void SetWidgetIndices(Widget const&amp; widget)\r\n{\r\n  widget.SetIndices([] { return <span style=\"color: blue;\">CalculateIndices()<\/span>; });\r\n}\r\n<\/pre>\n<p>but note that this changes the order of evaluation, since <code>Calculate\u00adIndices()<\/code> is called from inside the call to <code>Set\u00adIndices()<\/code>.<\/p>\n<p>Yes, it&#8217;s awkward, but at least it&#8217;s a workaround. You can make it slightly less awkward with a wrapper function:<\/p>\n<pre>void SetWidgetIndices(\r\n    Widget const&amp; widget,\r\n    winrt::com_array&lt;int32_t&gt;&amp;&amp; indices)\r\n{\r\n  widget.SetIndices(\r\n    [indices = std::move(indices)]() mutable\r\n    { return std::move(indices); });\r\n}\r\n<\/pre>\n<p>Next time, we&#8217;ll look at the implementation side of this method.<\/p>\n<p>\u00b9 You can use <code>IVector::Get\u00adMany()<\/code> to slurp out the elements, but that&#8217;s still a copy operation, which we are trying to avoid.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Survey the options and realize that the only choice is to go backward.<\/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-105987","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Survey the options and realize that the only choice is to go backward.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/105987","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=105987"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/105987\/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=105987"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=105987"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=105987"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}