{"id":106063,"date":"2021-12-30T07:00:00","date_gmt":"2021-12-30T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=106063"},"modified":"2021-12-17T21:37:56","modified_gmt":"2021-12-18T05:37:56","slug":"20211230-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20211230-00\/?p=106063","title":{"rendered":"The C++\/CX <CODE>String^<\/CODE> is not an object, even though it wears a hat"},"content":{"rendered":"<p>C++\/CX refers to Windows Runtime strings as <code>Platform::<wbr \/>String^<\/code> with a hat instead of a star. But even though the string wears a hat, it is not an <code>Object^<\/code>.<\/p>\n<p>The <code>String^<\/code> type is a representation of the Windows Runtime <code>HSTRING<\/code>. And of the <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20160615-00\/?p=93675\"> rules of <code>HSTRING<\/code><\/a> is that a null pointer is a valid <code>HSTRING<\/code>, and it represents the empty string, that is, a string with no characters.<\/p>\n<p>This makes <code>String^<\/code> a strange sort of beast.<\/p>\n<pre>String^ s = L\"\"; \/\/ sets s = nullptr\r\n<\/pre>\n<p>If you assign an empty string to it, you get <code>nullptr<\/code> back.<\/p>\n<pre>void f(String ^s)\r\n{\r\n    if (s) { \/* string is not empty *\/ }\r\n}\r\n<\/pre>\n<p>Testing a <code>String^<\/code> against <code>nullptr<\/code> tests whether the string is empty.<\/p>\n<pre>String ^s = nullptr; \/\/ represents empty string\r\nauto data = s-&gt;Data(); \/\/ legal! returns pointer to L\"\"\r\nauto length = s-&gt;Length(); \/\/ legal! returns 0.\r\nauto equal = s-&gt;Equals(L\"nope\"); \/\/ legal! returns false.\r\n<\/pre>\n<p>That&#8217;s right: I dereferenced a null pointer <i>and it felt good<\/i>.<\/p>\n<p>Calling methods on a null <code>String^<\/code> pointer is legal, and the operations are performed on an empty string.<\/p>\n<p>This weird behavior of null <code>String^<\/code> pointers has consequences beyond just strings. If you convert a null <code>String^<\/code> to <code>Object^<\/code> (a boxing operation), the null-ness is <i>preserved<\/i>:<\/p>\n<pre>String^ s = L\"\"; \/\/ s is nullptr\r\nObject^ o = s; \/\/ o is nullptr!\r\n<\/pre>\n<p>This differs from the behavior in other projections like C#, JavaScript, and C++\/WinRT, where boxing an empty string produces a non-null object (that in turn holds an empty string).<\/p>\n<p>The fact that a <code>String^<\/code> is not an <code>Object^<\/code> means that you cannot reinterpret between them.<\/p>\n<pre>String^ s = \/* some value *\/;\r\nObject^ o = reinterpret_cast&lt;Object^&gt;(s); \/\/ crash\r\n<\/pre>\n<p>The <code>reinterpret_cast<\/code> will treat a <code>String^<\/code> as an <code>Object^<\/code>. But a <code>String^<\/code> is secretly a <code>HSTRING<\/code>, whereas an <code>Object^<\/code> is secretly an <code>IInspectable*<\/code>. The reinterpret-cast tells the compiler to treat this <code>HSTRING<\/code> as if it were an <code>IInspectable*<\/code>, and bad things happen, since the compiler is going to try to call the <code>AddRef<\/code> method from the <code>IInspectable<\/code>&#8216;s vtable, but <code>HSTRING<\/code>s don&#8217;t have a vtable, much less a vtable with <code>AddRef<\/code> in slot 1.<\/p>\n<p>What you need to do is box the string into an object and unbox the object back into a string.<\/p>\n<pre>Object^o = s; \/\/ box the string into an object\r\nString^s = static_cast&lt;String^&gt;(o); \/\/ unbox the object into a string\r\n<\/pre>\n<p><b>Bonus chatter<\/b>: C++\/CX delegates are also not objects, even though they too wear hats.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A strange beast that thing is.<\/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-106063","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>A strange beast that thing is.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/106063","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=106063"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/106063\/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=106063"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=106063"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=106063"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}