{"id":103010,"date":"2019-10-18T07:00:00","date_gmt":"2019-10-18T14:00:00","guid":{"rendered":"http:\/\/devblogs.microsoft.com\/oldnewthing\/?p=103010"},"modified":"2019-10-17T21:40:07","modified_gmt":"2019-10-18T04:40:07","slug":"20191018-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20191018-00\/?p=103010","title":{"rendered":"C++\/WinRT implementation extension points: <CODE>abi_guard<\/CODE>, <CODE>abi_enter<\/CODE>, <CODE>abi_exit<\/CODE>, and <CODE>final_release<\/CODE>"},"content":{"rendered":"<p>C++\/WinRT provides a few extension points for implementations to customize default behavior of inspectable objects.<\/p>\n<p>When the last reference to an object is released, the object is destroyed. However, you may need to do some special cleanup while the object is still alive. The classic example of this is COM objects suffering <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20050927-00\/?p=34023\"> double-destruction due to a temporary refcount<\/a>, and the standard solution is to <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20050928-00\/?p=34013\"> artificially bump the reference count during destruction<\/a>.<\/p>\n<p>The C++\/WinRT library takes the standard solution and goes a step further: An implementation class can optionally implement a <code>final_release<\/code> method. If you provide such a method, then instead of destructing the object immediately upon the release of the final client reference, the C++\/WinRT library calls your <code>final_release<\/code> method with the last remaining reference to the object, in the form of a <code>unique_ptr<\/code>. The object is still alive (it has not started destructing), so you can do normal things with it, like pass it to another method that may temporarily bump its reference count. You can even <code>co_await<\/code> in your <code>final_release<\/code> if you need to do some asynchronous work before letting the object finally disappear.<\/p>\n<p>Normally, the object will destruct when the <code>unique_ptr<\/code> destructs, but you can hasten its death by calling <code>unique_ptr.reset()<\/code>, or you can postpone the inevitable by saving the <code>unique_ptr<\/code> somewhere. You can read <a href=\"https:\/\/kennykerr.ca\/2019\/06\/03\/cppwinrt-deferred-destruction\/\"> Kenny Kerr&#8217;s discussion of <code>final_release<\/code><\/a> for more details.<\/p>\n<p>The less commonly-used extension point is the <code>abi_guard<\/code> and its close friends <code>abi_enter<\/code> and <code>abi_exit<\/code>.<\/p>\n<p>If your implementation defines a method named <code>abi_enter<\/code>, then it will be called at the entry to every projected interface method (not counting the methods of <code>IInspectable<\/code>). Similarly, if you define a method named <code>abi_exit<\/code>, it will be called at the exit from every such method, but will not be called if <code>abi_enter<\/code> throws an exception. (It will be called if an exception is thrown by the method itself.)<\/p>\n<p>The calls to <code>abi_enter<\/code> and <code>abi_exit<\/code> are made with no parameters, and the return value is discarded.<\/p>\n<p>You might use <code>abi_enter<\/code> to, say, throw an <code>invalid_<code><\/code>state_<code><\/code>error<\/code> exception if a client tries to use an object after it has been put into an unusable state, say, after a <code>Shut\u00adDown<\/code> or <code>Disconnect<\/code> method. The C++\/WinRT iterator classes use this feature to throw a <code>invalid_<code><\/code>state_<code><\/code>error<\/code> exception in the <code>abi_enter<\/code> method if the underlying collection has changed.<\/p>\n<p>If the simple <code>abi_enter<\/code> and <code>abi_exit<\/code> methods aren&#8217;t fancy enough for you, you can define a nested class named <code>abi_guard<\/code>, in which case an instance of the <code>abi_guard<\/code> will be created on entry to each non-<code>IInspectable<\/code> projected interface method with a reference to the object as its constructor parameter. The <code>abi_guard<\/code> is destructed on exit from the method. You can put whatever extra state you like into the <code>abi_guard<\/code> class.<\/p>\n<p>Basically, the deal is that the default <code>abi_guard<\/code> calls <code>abi_enter<\/code> at construction and calls <code>abi_exit<\/code> at destruction. And the default <code>abi_enter<\/code> methods do nothing. You can therefore plug in either at the <code>abi_enter<\/code>\/<code>abi_exit<\/code> level, or at the <code>abi_guard<\/code> level.<\/p>\n<p>Note that these guards are used only if you invoke the methods via the projected interface. If you invoke the methods directly on the implementation object, then those calls go straight to the implementation without any guards.<\/p>\n<pre>struct Thing : ThingT&lt;Thing, IClosable&gt;\r\n{\r\n  void abi_enter();\r\n  void abi_exit();\r\n\r\n  void Close();\r\n};\r\n\r\nvoid example1()\r\n{\r\n  auto thing = make&lt;Thing&gt;();\r\n  thing.Close(); \/\/ calls abi_enter and abi_exit\r\n}\r\n\r\nvoid example2()\r\n{\r\n  auto thing = make_self&lt;Thing&gt;();\r\n  thing-&gt;Close(); \/\/ does not call abi_enter or abi_exit\r\n}\r\n<\/pre>\n<p>Note also that the guards are used only for the duration of the method call. If the method is a coroutine, the guard applies only until the <code>IAsyncXxx<\/code> is returned, not until the coroutine completes.<\/p>\n<pre>IAsyncAction CloseAsync()\r\n{\r\n  \/\/ guard is active here\r\n  DoSomething();\r\n\r\n  \/\/ guard becomes inactive once co_await starts,\r\n  \/\/ at which point CloseAsync returns an IAsyncAction.\r\n  co_await DoSomethingElseAsync();\r\n\r\n  \/\/ guard is not active here\r\n}\r\n<\/pre>\n<p>Guards are useful for specific cases like the &#8220;object that is no longer usable&#8221;, but their applicability in general is somewhat limited because they don&#8217;t know what method is being invoked. So you can&#8217;t do things like &#8220;If the object is not connected, then reject all method calls except for <code>Connect<\/code>.&#8221;<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Coming in, going out, and going away.<\/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-103010","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Coming in, going out, and going away.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103010","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=103010"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103010\/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=103010"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=103010"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=103010"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}