{"id":109431,"date":"2024-02-21T07:00:00","date_gmt":"2024-02-21T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=109431"},"modified":"2024-02-20T21:21:32","modified_gmt":"2024-02-21T05:21:32","slug":"20240221-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20240221-00\/?p=109431","title":{"rendered":"Once your object reaches <CODE>final_release<\/CODE>, you are committed to destructing it (eventually)"},"content":{"rendered":"<p>Some time ago, I discussed <a title=\"C++\/WinRT implementation extension points: abi_guard, abi_enter, abi_exit, and final_release\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20191018-00\/?p=103010\"> C++\/WinRT implementation extension points<\/a>, specifically the <code>final_<wbr \/>release<\/code> extension point which is given a <code>std::<wbr \/>unique_ptr<\/code> of the object which just experienced its final release. Since it happens before the destructor is run, you have extra flexibility in how you run the object down. A common reason for using <code>final_<wbr \/>release<\/code> is to ensure that the destructor runs in a specific execution environment. For example, <a title=\"Using C++\/WinRT's final_release to control which thread destructs your object\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20220722-00\/?p=106883\"> you can use it to ensure that the object&#8217;s destructor runs on a specific thread<\/a>.<\/p>\n<p>But one thing to keep in mind is that when you receive an object in your <code>final_<wbr \/>release<\/code>, it is no longer a COM object. It is now just a C++ object that is on its way to destruction. The expectation is that you will eventually destruct the object, though you may perform various cleanup operations before finally getting around to the destructor.<\/p>\n<p>Since it&#8217;s no longer a COM object, you can&#8217;t resurrect it and extend its COM lifetime. Its COM lifetime is over.<\/p>\n<p>For example, any outstanding COM weak references to the object will no longer resolve. As far as those weak references are concerned, the object is already gone. Even if you extend its C++ lifetime, its COM lifetime is already over. It has disappeared from the world of COM.<\/p>\n<p>The fact that the object&#8217;s COM lifetime has ended means that you can&#8217;t use <code>final_<wbr \/>release<\/code> to <a title=\"How can I expose a pre-existing block of memory as a Windows Runtime object without copying the data?\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20240126-00\/?p=109322\"> solve the <code>IMemory\u00adBuffer\u00adReference.<wbr \/>Closed<\/code> problem<\/a>. If you to raise the <code>Closed<\/code> event from <code>final_<wbr \/>release<\/code>, you&#8217;re giving out a COM reference to something that is no longer a COM object. I mean, you could still try to use it like a COM object, but when your <code>unique_ptr<\/code> destructs, the object will destruct even if the <code>Closed<\/code> event handler performed its own <code>AddRef<\/code> to extend the object&#8217;s lifetime.<\/p>\n<p>In theory, <code>final_<wbr \/>release<\/code> could have been designed so that it is called before the weak references are disconnected, and while the object is still a valid COM object whose lifetime can be extended. It&#8217;s bit tricky because you can&#8217;t just blindly subtract the strong reference; you have to prevent it from dropping to zero and ending the COM lifetime. But you don&#8217;t want that if your <code>final_<wbr \/>release<\/code> is for cleaning up the object, because that means that an outstanding COM weak reference could reacquire a strong reference to the COM object while you are in the process of cleaning it up. There would have to be a special function like <code>disconnect_<wbr \/>weak_<wbr \/>references<\/code> for <code>final_<wbr \/>release<\/code> to call. Not only would people probably forget to call it, but in the common case where you never intended to resurrect the object, the C++\/WinRT infrastructure went to a lot of effort to keep the weak references connected, only for you to immediately tell it, &#8220;Oh, nevermind.&#8221;<\/p>\n<p>Since the vast majority of usage of <code>final_<wbr \/>release<\/code> is cleaning up the object in an organized manner, cases for which you want the weak references to be disconnected, C++\/WinRT is biased toward that common case. If you want the other rare case, you can use the trick we used when we <a title=\"How can I expose a pre-existing block of memory as a Windows Runtime object without copying the data?\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20240126-00\/?p=109322\"> implemented the <code>IMemory\u00adBuffer\u00adReference.<wbr \/>Closed<\/code> event<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Don&#8217;t try to resurrect it.<\/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-109431","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Don&#8217;t try to resurrect it.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109431","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=109431"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109431\/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=109431"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=109431"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=109431"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}