{"id":313,"date":"2014-08-07T07:00:00","date_gmt":"2014-08-07T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2014\/08\/07\/since-clean-up-functions-cant-fail-you-have-to-soldier-on\/"},"modified":"2014-08-07T07:00:00","modified_gmt":"2014-08-07T07:00:00","slug":"since-clean-up-functions-cant-fail-you-have-to-soldier-on","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20140807-00\/?p=313","title":{"rendered":"Since clean-up functions can&#039;t fail, you have to soldier on"},"content":{"rendered":"<p>\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2008\/01\/07\/7011066.aspx\">\nClean-up functions can&#8217;t fail<\/a>,\nso what do you do if you encounter a failure in your clean-up function?\n<\/p>\n<p>\nYou have to keep cleaning up.\n<\/p>\n<p>\nSome people like to follow this pattern for error checking:\n<\/p>\n<pre>\nHRESULT Function()\n{\n  hr = SomeFunction();\n  if (FAILED(hr))) goto Exit;\n  hr = AnotherFunction();\n  if (FAILED(hr))) goto Exit;\n  ... and so on until ...\n  hr = S_OK;\nExit:\n    return hr;\n}\n<\/pre>\n<p>\nAnd some like to put it inside a cute\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2005\/01\/06\/347666.aspx\">\nflow control macro<\/a>\nlike\n<\/p>\n<pre>\n#define CHECK_HRESULT(hr) if (FAILED(hr)) goto Exit;\n<\/pre>\n<p>\nor even\n<\/p>\n<pre>\n#define CHECK_HRESULT(f) if (FAILED(hr = (f))) goto Exit;\n<\/pre>\n<p>\nWhatever floats your boat.\n<\/p>\n<p>\nBut you have to be careful if using this pattern in a clean-up function,\nbecause you might end up not actually cleaning up.\nFor example:\n<\/p>\n<pre>\nHRESULT Widget::Close()\n{\n    HRESULT hr;\n    CHECK_HRESULT(DisconnectDoodad(m_hDoodad));\n    m_hDoodad = nullptr;\n    for (int i = 0; i &lt; ARRRAYSIZE(GadgetArray); i++) {\n        CHECK_HRESULT(DestroyGadget(m_rghGadget[i]));\n        m_rghGadget[i] = nullptr;\n    }\n    hr = S_OK;\nExit:\n    return hr;\n}\n<\/pre>\n<p>\nWhat if there is an error disconnecting the doodad?\n(Maybe you got\n<code>RPC_E_SERVER_DIED<\/code>\nbecause the doodad lives on a remote server which crashed.)\nThe cleanup code treats this as an error and\nskips destroying the gadget.\nBut what can the caller do about this?\nNothing, that&#8217;s what.\nEventually you get a bug that says,\n&#8220;On an unreliable network, we leak gadgets like crazy.&#8221;\n<\/p>\n<p>\nOr worse, what if you&#8217;re doing this in your destructor.\nYou have nowhere to report the error.\nThe caller simply expects that when the object is destroyed,\nall its resources are released.\n<\/p>\n<p>\nSo release as much as you can.\nIf something goes wrong with one of them,\nkeep going, because there&#8217;s still other stuff to clean up.\n<\/p>\n<p>\n<b>Related<\/b>:\n<a HREF=\"http:\/\/www.parashift.com\/c++-faq-lite\/exceptions.html#faq-17.9\">\nNever throw an exception from a destructor<\/a>.\n<\/p>\n<p>\n<b>Bonus chatter<\/b>:\nYes, I know that you can avoid this problem by wrapping the\nDoodad and Gadget handles\ninside a class which disconnects\/destroys on destruction.\nThat&#8217;s not my point.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Clean-up functions can&#8217;t fail, so what do you do if you encounter a failure in your clean-up function? You have to keep cleaning up. Some people like to follow this pattern for error checking: HRESULT Function() { hr = SomeFunction(); if (FAILED(hr))) goto Exit; hr = AnotherFunction(); if (FAILED(hr))) goto Exit; &#8230; and so on [&hellip;]<\/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-313","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Clean-up functions can&#8217;t fail, so what do you do if you encounter a failure in your clean-up function? You have to keep cleaning up. Some people like to follow this pattern for error checking: HRESULT Function() { hr = SomeFunction(); if (FAILED(hr))) goto Exit; hr = AnotherFunction(); if (FAILED(hr))) goto Exit; &#8230; and so on [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/313","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=313"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/313\/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=313"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=313"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=313"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}