{"id":105872,"date":"2021-11-04T07:00:00","date_gmt":"2021-11-04T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=105872"},"modified":"2023-09-16T07:15:39","modified_gmt":"2023-09-16T14:15:39","slug":"20211104-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20211104-00\/?p=105872","title":{"rendered":"How can I prevent myself from accessing a lambda captured variable or a parameter after I&#8217;m done with it?"},"content":{"rendered":"<p>We saw last time that you can have your cake and eat it too: You can have a capturing lambda coroutine <a title=\"A capturing lambda can be a coroutine, but you have to save your captures while you still can\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20211103-00\/?p=105870\"> provided you copy the captures to the coroutine frame before the coroutine&#8217;s first suspension point<\/a>. From that point onward, you use the copies in the frame instead of the original captured variables, because the original captured variables may no longer exist!<\/p>\n<p>You therefore must exercise willpower to resist the temptation to access those captured variables, since they are now poison. Is there a way to help stop yourself from doing a bad thing? Like, put a &#8220;Do not touch&#8221; sticker on the captured variable?<\/p>\n<p>We can do this by taking advantage of <i>name hiding<\/i>, which also goes by the name <i>shadowing<\/i>. Name hiding is normally something you are scared of, because it often happens by mistake:<\/p>\n<pre>int open_or_alt(char const* name, char const* altname)\r\n{\r\n    int fd = open(name, 0);\r\n    if (fd == -1 &amp;&amp; errno == ENOENT) {\r\n        \/\/ accidentally shadowed outer \"fd\" variable\r\n        int fd = open(altname, 0);\r\n    }\r\n    return fd;\r\n}\r\n<\/pre>\n<p>In our case, we can use it on purpose. Suppose we define some type, call it <code>hide_name<\/code>, and we use it to hide the names of things we don&#8217;t want to see any more.<\/p>\n<pre>void RegisterClickHandler(Button const&amp; button, int key)\r\n{\r\n    button.Click([key](auto&amp;&amp;, auto&amp;&amp;)\r\n        -&gt; winrt::fire_and_forget\r\n        {\r\n            auto copiedKey = key;\r\n            <span style=\"border: solid 1px currentcolor;\">hide_name key; \/\/ \"key is now dead to me\"<\/span>\r\n            co_await winrt::resume_background();\r\n            NotifyClick(key); \/\/ want this to be an error\r\n        });\r\n}\r\n<\/pre>\n<p>What we&#8217;re doing is declaring a local variable named <code>key<\/code> which hides the captured variable with the same name. Any attempt to use <code>key<\/code> after the point of declaration will use the local variable version and not the captured variable version. Let&#8217;s assume that <code>hide_name<\/code> is carefully defined so that using it instead of the hidden variable has maximum likelihood of generating a compiler error. (We&#8217;ll look at how we can do this later.)<\/p>\n<p>You can also hide parameters, which is handy if you have a coroutine that must accept parameters by reference (say, for some compatibility reason), but needs to access them after a suspension point.<\/p>\n<pre>\/\/ This used to refresh synchronously, but now we refresh\r\n\/\/ asynchronously. The parameter is still passed by reference\r\n\/\/ for compatibility.\r\nwinrt::fire_and_forget Refresh(winrt::com_ptr&lt;Widget&gt; const&amp; widget)\r\n{\r\n    auto copiedWidget = widget;\r\n    <span style=\"border: solid 1px currentcolor;\">hide_name widget;<\/span>\r\n    co_await winrt::resume_background();\r\n    copiedWidget-&gt;Reset();\r\n    copiedWidget-&gt;Reload();\r\n}\r\n<\/pre>\n<p>Note that you can hide names from outer scopes. You cannot hide a name from the same scope.<\/p>\n<pre>winrt::fire_and_forget GiveAwayTheWidget()\r\n{\r\n    Widget widget;\r\n    widget.Initialize();\r\n    GiveAway(std::move(widget));\r\n\r\n    \/\/ Try to prevent accidentally using a moved-from variable.\r\n    hide_name widget; \/\/ error\r\n\r\n    ...\r\n}\r\n<\/pre>\n<p>Since <code>hide_name blah;<\/code> is a declaration, you can hide multiple names by separate them with commas.<\/p>\n<pre>    hide_name a, b, c; \/\/ all three names are hidden\r\n<\/pre>\n<p>Okay, so the big question is &#8220;What should <code>hide_name<\/code> be in order to maximize the likelihood that using it will result in a compiler error?&#8221;<\/p>\n<p>I came up with this:<\/p>\n<pre>using hide_name = void(struct hidden_name);\r\n<\/pre>\n<p>This says that <code>hide_name<\/code> is an alias for a function that accepts an incomplete type called <code>hidden_name<\/code> and which returns a <code>void<\/code>. When you write<\/p>\n<pre>hide_name a;\r\n<\/pre>\n<p>what you&#8217;re really saying is &#8220;<code>a<\/code> is a function that accepts an object of type <code>hidden_name<\/code> and which returns <code>void<\/code>.&#8221; It&#8217;s just a function declaration, not a variable declaration. But function names are still names, so they participate in name hiding.<\/p>\n<p>Using the name <code>a<\/code> by itself will decay to a function pointer, which is not convertible to anything interesting. In particular, you can&#8217;t even do this:<\/p>\n<pre>void* p = &amp;a;\r\n<\/pre>\n<p>Function pointers are not compatible with data pointers, so this catches the case where somebody accidentally tried to pass the address of a captured variable to something that accepts a <code>void*<\/code>.<\/p>\n<p>You can&#8217;t do arithmetic on function pointers, so those will generate errors. And you can&#8217;t call the function pointer because its sole parameter is <code>hidden_name<\/code> which is an incomplete type.<\/p>\n<p>Functions cannot be assigned to, so that blocks any attempt to write to <code>a<\/code>.<\/p>\n<p>If somehow somebody gets past all these barriers (say by explicitly casting to <code>uintptr_t<\/code> on an implementation that supports it), they will fail at link time with an unresolved external complaining that there is no function named <code>a<\/code> that accepts a <code>hidden_name<\/code> as a parameter. (No such function can exist because <code>hidden_name<\/code> is an incomplete type.)<\/p>\n<p>Here&#8217;s what I found in my experiments:<\/p>\n<p>Accessing the variable in various ways.<\/p>\n<pre>void test(int);\r\nint i;\r\nhide_name a;\r\n\r\n\/\/ All accept this. \"v\" is a pointer to function.\r\n\/\/ You will probably get errors when you try to use \"v\", though.\r\nauto v = a;\r\n\r\n\/\/ msvc: C2440: cannot convert from 'hide_name (__cdecl *)' to 'int'\r\n\/\/ gcc: invalid conversion from 'void (*)(hidden_name)' to 'int' in assignment\r\n\/\/ clang: assigning to 'int' from incompatible type 'hide_name'\r\n\/\/ icc: a value of type \"hide_name *\" cannot be assigned to an entity of type \"int\"\r\ni = a;\r\n\r\n\/\/ msvc: C2659: '=': function as left operand\r\n\/\/ gcc: assignment of function 'void a(hidden_name)'\r\n\/\/ clang: non-object type 'hide_name' is not assignable\r\n\/\/ icc: expression must be a modifiable lvalue\r\na = i;\r\n\r\n\/\/ msvc: cannot convert argument 1 from 'hide_name (__cdecl *)' to 'int'\r\n\/\/ gcc: invalid conversion from 'void (*)(hidden_name)' to 'int'\r\n\/\/ clang: no matching function for call to 'test'\r\n\/\/ icc: argument of type \"hide_name *\" is incompatible with parameter of type \"int\"\r\ntest(a);\r\n\r\n\/\/ msvc: C2296: '+': illegal, left operand has type 'hide_name (__cdecl *)'\r\n\/\/ gcc: pointer to a function used in arithmetic\r\n\/\/ clang: arithmetic on a pointer to the function type 'hide_name'\r\n\/\/ icc: a value of type \"hide_name *\" cannot be assigned to an entity of type \"int\"\r\ni = a + 1;\r\n\r\n\/\/ msvc: C2296: '+': illegal, left operand has type 'hide_name (__cdecl *)'\r\n\/\/ gcc: pointer to a function used in arithmetic\r\n\/\/ clang: arithmetic on a pointer to the function type 'hide_name'\r\n\/\/ icc: NO ERROR AT COMPILE TIME! (Fails to link.)\u00b9\r\nauto p = a + 1;\r\n\r\n\/\/ msvc: C2070: 'hide_name': illegal sizeof operand\r\n\/\/ gcc: ISO C++ forbids applying 'sizeof' to an expression of function type\u00b2\r\n\/\/ clang: invalid application of 'sizeof' to a function type\r\n\/\/ icc: warning: operand of sizeof may not be a function\r\nauto size = sizeof(a);\r\n\r\n\/\/ msvc: C228: left of '.method' must have class\/struct\/union\r\n\/\/ gcc: request for member 'method' in 'a', which is of non-class type 'hide_name'\r\n\/\/ clang: member reference base type 'hide_name' is not a structure or union\r\n\/\/ icc: expression must have class type\r\na.method();\r\n<\/pre>\n<p>Furthermore, since this is a function declaration and not a variable declaration, you are less likely to get &#8220;unused local variable&#8221; errors. gcc, clang, and icc ignore the unused function declaration.<\/p>\n<p>Unfortunately, the place where this trick is most useful is in coroutines, and that&#8217;s where compilers today are the weakest. MSVC 19.28 was okay with it, but it seems that MSVC 19.29 does complain about unused function declarations in coroutines. As of this writing, <a href=\"https:\/\/developercommunity.visualstudio.com\/t\/Unused-function-declaration-in-coroutine\/1507689?space=62&amp;scope=follow\"> a fix is pending release<\/a>. [<b>Update February 15, 2022<\/b>: It is fixed in <a href=\"https:\/\/devblogs.microsoft.com\/visualstudio\/visual-studio-2022-17-1-is-now-available\/\">Visual Studio 2022 Version 17.1<\/a>.] gcc, on the other hand, <a href=\"https:\/\/gcc.godbolt.org\/z\/o58Mbasz7\"> totally freaks out about function declarations in coroutines<\/a>: Version 11 produces the inscrutable error &#8220;data member &#8216;enclosing_function()::_Z18enclosing_functionv.frame::__a.2.3&#8217; invalid declared function.&#8221; Version 12 blows up with <a href=\"https:\/\/gcc.godbolt.org\/z\/sW9n3cdz4\"> an internal compiler error<\/a>.<\/p>\n<p>So maybe you should hold off on this for a bit longer.<\/p>\n<p>\u00b9 For some reason, icc treats the size of a function as 1. Sometimes it warns you that it&#8217;s making this nonstandard decision. Other times, it just does it without telling you.<\/p>\n<p>\u00b2 I find it amusing that one of the gcc error messages says &#8220;ISO C++ forbids&#8230;&#8221;, as if it&#8217;s saying &#8220;Hey, I totally would let you get away with this, but those pesky C++ standard folks tell me I&#8217;m not allowed to. So don&#8217;t blame me!&#8221;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Name-hiding on purpose.<\/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-105872","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Name-hiding on purpose.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/105872","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=105872"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/105872\/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=105872"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=105872"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=105872"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}