{"id":34013,"date":"2005-09-28T10:00:10","date_gmt":"2005-09-28T10:00:10","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2005\/09\/28\/avoiding-double-destruction-when-an-object-is-released\/"},"modified":"2023-08-22T17:04:23","modified_gmt":"2023-08-23T00:04:23","slug":"avoiding-double-destruction-when-an-object-is-released","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20050928-10\/?p=34013","title":{"rendered":"Avoiding double-destruction when an object is released"},"content":{"rendered":"<p><a title=\"COM object destructors are very sensitive functions\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20050927-13\/?p=34023\"> As we saw last time, trying to do too much in one&#8217;s destructor can lead to an object being destroyed twice<\/a>. The standard way to work around this problem is to set an artificial reference count during destruction.<\/p>\n<pre>class MyObject : public IUnknown\r\n{\r\n ...\r\n ULONG Release()\r\n {\r\n  LONG cRef = InterlockedDecrement(&amp;m_cRef);\r\n  if (cRef == 0) {\r\n   <span style=\"border: solid 1px currentcolor;\">m_cRef = DESTRUCTOR_REFCOUNT;<\/span>\r\n   delete this;\r\n  }\r\n  return cRef;\r\n }\r\n ...\r\nprivate:\r\n }\r\n <span style=\"border: solid 1px currentcolor;\">enum { DESTRUCTOR_REFCOUNT = 42 };<\/span>\r\n ~MyObject()\r\n {\r\n  if (m_fNeedSave) Save();\r\n  <span style=\"border: solid 1px currentcolor;\">assert(m_cRef == DESTRUCTOR_REFCOUNT);<\/span>\r\n }\r\n};\r\n<\/pre>\n<p>If you have a common implementation of <code>IUnknown<\/code>, you can set the reference count to <code>DESTRUCTOR_REFCOUNT<\/code> in your implementation of <code>IUnknown::Release<\/code> like we did here, and assert that the value is correct in your implementation&#8217;s destructor. Since C++ runs base class destructors after derived class destructors, your base class destructor will check the reference count after the derived class has done its cleanup.<\/p>\n<p>By setting the reference count to an artificial non-zero value, any <code>AddRef()<\/code> and <code>Release()<\/code> calls that occur will not trigger a duplicate destruction (assuming of course that nobody in the destructor path has a bug that causes them to over-release). The assertion at the end ensures that no new references to the object have been created during destruction.<\/p>\n<p>This is really more of a workaround than a rock-solid solution, because it assumes that no functions called during the destruction sequence retain a reference to the object beyond the function&#8217;s return. This is in general not something you can assume about COM. In general, a method is free to call <code>AddRef<\/code> and hang onto a pointer to an object in order to complete the requested operation later. Some methods (such as <a href=\"http:\/\/msdn.microsoft.com\/workshop\/components\/com\/reference\/ifaces\/ipersistpropertybag\/load.asp\"> the <code>IPersistPropertyBag::Load<\/code> method<\/a>) explicitly forbid such behavior, but these types of methods are more the exception rather than the rule.<\/p>\n<p><strong>Exercise<\/strong>: Why is it safe to perform a simple assignment <code>m_cRef = DESTRUCTOR_REFCOUNT<\/code> instead of the more complicated <code>InterlockedExchangeAdd(&amp;m_cRef, DESTRUCTOR_REFCOUNT)<\/code>?<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The trick of the artificial reference count.<\/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-34013","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>The trick of the artificial reference count.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/34013","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=34013"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/34013\/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=34013"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=34013"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=34013"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}