{"id":2051,"date":"2014-02-17T13:00:22","date_gmt":"2014-02-17T13:00:22","guid":{"rendered":"http:\/\/writeasync.net\/?p=2051"},"modified":"2014-02-16T09:50:52","modified_gmt":"2014-02-16T09:50:52","slug":"avoid-memory-leaks-through-design","status":"publish","type":"post","link":"http:\/\/writeasync.net\/?p=2051","title":{"rendered":"Avoid memory leaks by design"},"content":{"rendered":"<p>There are many tools and techniques out there to help detect <a href=\"http:\/\/en.wikipedia.org\/wiki\/Memory_leak\">memory leaks<\/a>. For instance, you can <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/hardware\/ff560134(v=vs.85).aspx\">monitor performance counters<\/a> for unexpected memory growth. Once a leak is suspected, <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ff560206(v=vs.85).aspx\">UMDH<\/a> might be able to help you pinpoint the culprit. However, when it comes to memory management, &#8220;<a href=\"http:\/\/www.ushistory.org\/franklin\/quotable\/quote67.htm\">an ounce of prevention is worth a pound of cure<\/a>.&#8221; Treat memory leaks not as code defects which require superficial fixes but as the <em>design issues<\/em> that they are.<\/p>\n<p>In modern C++ (at least since, say, <a href=\"http:\/\/en.wikipedia.org\/wiki\/C%2B%2B11\">C++11<\/a>), the situation can be summed up thusly:<\/p>\n<ul>\n<li>Memory leaks are a design issue.<\/li>\n<li>In the vast majority of cases, the specific design issue is unclear <a href=\"http:\/\/en.wikipedia.org\/wiki\/Object_lifetime\">object lifetime<\/a> arising from the use of raw pointers.<\/li>\n<li>The solution is either eliminating the pointers or switching to <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/hh279674.aspx\">smart pointers<\/a>.<\/li>\n<\/ul>\n<p>I admit that this terse synopsis is rather unsatisfying. So rather than leaving it that, let&#8217;s look at some specific examples. Note that the sample code all assumes this &#8220;<code>Common.h<\/code>&#8221; header file:<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\n#pragma once\r\n\r\n#include &lt;memory&gt;\r\n#include &lt;iostream&gt;\r\n#include &lt;string&gt;\r\n#include &lt;atomic&gt;\r\n#include &lt;sstream&gt;\r\n\r\n\/\/ Helps track leaked allocations\r\nstruct Counter { static std::atomic&lt;int&gt; N; };\r\nstd::atomic&lt;int&gt; Counter::N(0);\r\n\r\n\/\/ Base class to disallow copy by assignment or construction.\r\nstruct DenyCopy\r\n{\r\n    DenyCopy() { }\r\n    ~DenyCopy() { }\r\n    DenyCopy(DenyCopy const &amp;) = delete;\r\n    DenyCopy &amp; operator = (DenyCopy const &amp;) = delete;\r\n};\r\n\r\n\/\/ The sample class which we'll be allocating\/freeing. We trace on\r\n\/\/ construction\/destruction, as well as dynamic &#x5B;de]allocation\r\n\/\/ (via overloaded new\/delete operators).\r\ntemplate&lt;typename TCounter&gt;\r\nclass MyClass_T : private DenyCopy\r\n{\r\npublic:\r\n    MyClass_T(std::wstring const &amp; name)\r\n        : name_(name)\r\n    {\r\n        ++TCounter::N;\r\n        std::wcout &lt;&lt; L&quot;MyClass:&quot; &lt;&lt; name_ &lt;&lt; std::endl;\r\n    }\r\n\r\n    ~MyClass_T()\r\n    {\r\n        std::wcout &lt;&lt; L&quot;~MyClass:&quot; &lt;&lt; name_ &lt;&lt; std::endl;\r\n        --TCounter::N;\r\n    }\r\n\r\n    void * operator new(size_t size)\r\n    {\r\n        std::wcout &lt;&lt; L&quot;(Dynamic allocation)&quot; &lt;&lt; endl;\r\n        return ::operator new(size);\r\n    }\r\n\r\n    void operator delete(void * ptr)\r\n    {\r\n        ::operator delete(ptr);\r\n        std::wcout &lt;&lt; L&quot;(Dynamic deallocation)&quot; &lt;&lt; endl;\r\n    }\r\n\r\n    std::wstring const &amp; get_Name() const { return name_; }\r\n\r\nprivate:\r\n    std::wstring name_;\r\n};\r\n\r\n\/\/ RAII wrapper to trace on function enter\/leave.\r\nclass FuncTrace : private DenyCopy\r\n{\r\npublic:\r\n    FuncTrace(wchar_t const * name)\r\n        : name_(name)\r\n    {\r\n        std::wcout &lt;&lt; L&quot;{ Enter &quot; &lt;&lt; name_ &lt;&lt; std::endl;\r\n    }\r\n\r\n    ~FuncTrace()\r\n    {\r\n        std::wcout &lt;&lt; L&quot;} Leave &quot; &lt;&lt; name_ &lt;&lt; std::endl;\r\n    }\r\n\r\nprivate:\r\n    wchar_t const * name_;\r\n};\r\n\r\n\/\/ Some helpful typedefs\r\ntypedef MyClass_T&lt;Counter&gt; MyClass;\r\ntypedef std::unique_ptr&lt;MyClass&gt; MyClassUPtr;\r\ntypedef std::shared_ptr&lt;MyClass&gt; MyClassSPtr;\r\n<\/pre>\n<h2>Elimination of pointers<\/h2>\n<p>Pointers typically come into play when using dynamic memory, such as when objects are <a href=\"http:\/\/www.gotw.ca\/gotw\/009.htm\">allocated in the &#8220;free store&#8221;<\/a> by calling <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/kewsb8ba.aspx\"><code>new<\/code><\/a>. Often you simply don&#8217;t need dynamic memory which means you can <strong>eliminate the associated pointers<\/strong>. <a href=\"http:\/\/en.wikipedia.org\/wiki\/Stack-based_memory_allocation\">Stack allocation<\/a> is sufficient when you are dealing with a small object whose lifetime is no greater than the local scope. Consider this example:<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\nvoid QuestionableDynamicAllocation()\r\n{\r\n    FuncTrace t(__FUNCTIONW__);\r\n    MyClass * p = new MyClass(L&quot;probably-should-stack-allocate&quot;);\r\n    wcout &lt;&lt; L&quot;Using &quot; &lt;&lt; p-&gt;get_Name() &lt;&lt; L&quot;...&quot; &lt;&lt; endl;\r\n    \/\/ ... do more things ...\r\n    delete p;\r\n}\r\n\r\nvoid BetterStackAllocation()\r\n{\r\n    FuncTrace t(__FUNCTIONW__);\r\n    MyClass c(L&quot;on-the-stack&quot;);\r\n    wcout &lt;&lt; L&quot;Using &quot; &lt;&lt; c.get_Name() &lt;&lt; L&quot;...&quot; &lt;&lt; endl;\r\n    \/\/ ... do more things ...\r\n    \/\/ yay, no need for delete!\r\n}\r\n\r\nint wmain(int argc, wchar_t ** argv)\r\n{\r\n    QuestionableDynamicAllocation();\r\n    BetterStackAllocation();\r\n    wcout &lt;&lt; L&quot;Final count: &quot; &lt;&lt; Counter::N &lt;&lt; endl;\r\n    return 0;\r\n}\r\n<\/pre>\n<p>The output:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n{ Enter QuestionableDynamicAllocation\r\n(Dynamic allocation)\r\nMyClass:probably-should-stack-allocate\r\nUsing probably-should-stack-allocate...\r\n~MyClass:probably-should-stack-allocate\r\n(Dynamic deallocation)\r\n} Leave QuestionableDynamicAllocation\r\n{ Enter BetterStackAllocation\r\nMyClass:on-the-stack\r\nUsing on-the-stack...\r\n~MyClass:on-the-stack\r\n} Leave BetterStackAllocation\r\nFinal count: 0\r\n<\/pre>\n<p>Stack allocation is clearly sufficient in this case given that the object is expected to be destructed before the function exits. Using the stack here also gives us the bonus of exception safety &#8212; <code>delete<\/code> may not be called if any of the intervening code throws an exception.<\/p>\n<h2>Scoped smart pointer<\/h2>\n<p>Okay, so let&#8217;s say we really do need dynamic allocation &#8212; perhaps we have limited stack space. In that case, <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ee410601.aspx\"><code>unique_ptr<\/code><\/a> can be used to safely wrap <code>new<\/code> and <code>delete<\/code>:<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\nvoid ScopedUse(bool leaveEarly)\r\n{\r\n    FuncTrace t(__FUNCTIONW__);\r\n    MyClassUPtr p = make_unique&lt;MyClass&gt;(L&quot;this-scope-only&quot;);\r\n    wcout &lt;&lt; L&quot;I'm doing something with &quot; &lt;&lt; p-&gt;get_Name() &lt;&lt; endl;\r\n    if (leaveEarly)\r\n    {\r\n        wcout &lt;&lt; L&quot;Leaving now!&quot; &lt;&lt; endl;\r\n        return;\r\n    }\r\n\r\n    wcout &lt;&lt; L&quot;Doing more with &quot; &lt;&lt; p-&gt;get_Name() &lt;&lt; endl;\r\n}\r\n\r\nint wmain(int argc, wchar_t ** argv)\r\n{\r\n    ScopedUse(false);\r\n    ScopedUse(true);\r\n    wcout &lt;&lt; L&quot;Final count: &quot; &lt;&lt; Counter::N &lt;&lt; endl;\r\n    return 0;\r\n}\r\n<\/pre>\n<p>The output:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n{ Enter ScopedUse\r\n(Dynamic allocation)\r\nMyClass:this-scope-only\r\nI'm doing something with this-scope-only\r\nDoing more with this-scope-only\r\n~MyClass:this-scope-only\r\n(Dynamic deallocation)\r\n} Leave ScopedUse\r\n{ Enter ScopedUse\r\n(Dynamic allocation)\r\nMyClass:this-scope-only\r\nI'm doing something with this-scope-only\r\nLeaving now!\r\n~MyClass:this-scope-only\r\n(Dynamic deallocation)\r\n} Leave ScopedUse\r\nFinal count: 0\r\n<\/pre>\n<p>The object is guaranteed to be destroyed in any normal function exit condition, exceptional or successful, even in the early return case demonstrated above &#8212; a typical source of leaks in code using raw pointers.<\/p>\n<h2>Safe transfer of ownership<\/h2>\n<p>Sometimes we need to create and prepare a dynamically allocated object but ultimately pass it off to some other place, after which the callee is responsible for its lifetime. Again, <code>unique_ptr<\/code> comes to our rescue here with its implementation of <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/dd293668.aspx\">move semantics<\/a>. This allows us to safely transfer ownership so that we avoid <a href=\"http:\/\/www.parashift.com\/c++-faq-lite\/double-delete-disaster.html\">double deletion<\/a> or no deletion:<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\nvoid NewOwner(MyClassUPtr p)\r\n{\r\n    FuncTrace t(__FUNCTIONW__);\r\n    wcout &lt;&lt; L&quot;I now own &quot; &lt;&lt; p-&gt;get_Name() &lt;&lt; endl;\r\n}\r\n\r\nvoid CreateAndTransfer()\r\n{\r\n    FuncTrace t(__FUNCTIONW__);\r\n    MyClassUPtr p = make_unique&lt;MyClass&gt;(L&quot;to-be-moved&quot;);\r\n    \/\/ ... do some other things here ...\r\n    \/\/ Now give the object away\r\n    NewOwner(move(p));\r\n    if (!p)\r\n    {\r\n        wcout &lt;&lt; L&quot;I can't use this instance anymore.&quot; &lt;&lt; endl;\r\n    }\r\n}\r\n\r\nint wmain(int argc, wchar_t ** argv)\r\n{\r\n    CreateAndTransfer();\r\n    wcout &lt;&lt; L&quot;Final count: &quot; &lt;&lt; Counter::N &lt;&lt; endl;\r\n    return 0;\r\n}\r\n<\/pre>\n<p>Note that we have to use <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ee390941.aspx\"><code>move<\/code><\/a> for the code to compile &#8212; you cannot otherwise pass a <code>unique_ptr<\/code> by value as this would lead to unclear ownership. The output:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n{ Enter CreateAndTransfer\r\n(Dynamic allocation)\r\nMyClass:to-be-moved\r\n{ Enter NewOwner\r\nI now own to-be-moved\r\n} Leave NewOwner\r\n~MyClass:to-be-moved\r\n(Dynamic deallocation)\r\nI can't use this instance anymore.\r\n} Leave CreateAndTransfer\r\nFinal count: 0\r\n<\/pre>\n<h2>Safe reassignment<\/h2>\n<p>Consider this <strong>very bad code<\/strong> which implements a retry loop and some macros for &#8220;safe&#8221; cleanup:<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\n#define BEGIN_RETRY_LOOP(maxAttempt) \\\r\n{ int retryMaxAttempt = (maxAttempt); int retryAttempt = 0; for (; retryAttempt &lt; retryMaxAttempt; ++retryAttempt)\r\n\r\n#define END_RETRY_LOOP \\\r\nif (retryAttempt == retryMaxAttempt) goto Cleanup; }\r\n\r\n#define FREE(ptr) { if (ptr) { delete ptr; ptr = nullptr; } }\r\n\r\nbool Validate(MyClass * p)\r\n{\r\n    return p-&gt;get_Name() == wstring(L&quot;Attempt-1&quot;);\r\n}\r\n\r\nvoid LeakyReassignment()\r\n{\r\n    FuncTrace t(__FUNCTIONW__);\r\n    MyClass * p;\r\n    BEGIN_RETRY_LOOP(5)\r\n    {\r\n        wstringstream wss;\r\n        wss &lt;&lt; L&quot;Attempt-&quot; &lt;&lt; retryAttempt;\r\n        p = new MyClass(wss.str());\r\n        bool isValid = Validate(p);\r\n        if (isValid)\r\n        {\r\n            break;\r\n        }\r\n    }\r\n    END_RETRY_LOOP\r\n\r\n    \/\/ ...\r\n    wcout &lt;&lt; L&quot;I have a valid pointer &quot; &lt;&lt; p-&gt;get_Name() &lt;&lt; endl;\r\n    \/\/ ... more stuff here ...\r\nCleanup:\r\n    FREE(p);\r\n}\r\n\r\nint wmain(int argc, wchar_t ** argv)\r\n{\r\n    LeakyReassignment();\r\n    wcout &lt;&lt; L&quot;Final count: &quot; &lt;&lt; Counter::N &lt;&lt; endl;\r\n    return 0;\r\n}\r\n<\/pre>\n<p>The output shows the obvious leak here:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n{ Enter LeakyReassignment\r\n(Dynamic allocation)\r\nMyClass:Attempt-0\r\n(Dynamic allocation)\r\nMyClass:Attempt-1\r\nI have a valid pointer Attempt-1\r\n~MyClass:Attempt-1\r\n(Dynamic deallocation)\r\n} Leave LeakyReassignment\r\nFinal count: 1\r\n<\/pre>\n<p>Since the object was declared &#8220;invalid&#8221; on the first attempt, a new object was allocated on the second attempt, overwriting the original pointer. That first object is never released. While this could be &#8220;fixed&#8221; by adding a <code>FREE(p)<\/code> inside an <code>else<\/code> clause, we should instead stay very far away from the defective &#8220;<code>if (failed) goto cleanup<\/code>&#8221; pattern and <em>use real C++<\/em>. Let&#8217;s look at a better implementation that uses <code>unique_ptr<\/code> and ditches the ugly macros:<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\nvoid CorrectReassignment()\r\n{\r\n    FuncTrace t(__FUNCTIONW__);\r\n    MyClassUPtr p;\r\n    for (int retryAttempt = 0; retryAttempt &lt; 5; ++retryAttempt)\r\n    {\r\n        wstringstream wss;\r\n        wss &lt;&lt; L&quot;Attempt-&quot; &lt;&lt; retryAttempt;\r\n        p = make_unique&lt;MyClass&gt;(wss.str());\r\n        bool isValid = Validate(p.get());\r\n        if (isValid)\r\n        {\r\n            break;\r\n        }\r\n    }\r\n\r\n    \/\/ ...\r\n    wcout &lt;&lt; L&quot;I have a valid pointer &quot; &lt;&lt; p-&gt;get_Name() &lt;&lt; endl;\r\n    \/\/ ... more stuff here ...\r\n}\r\n\r\nint wmain(int argc, wchar_t ** argv)\r\n{\r\n    CorrectReassignment();\r\n    wcout &lt;&lt; L&quot;Final count: &quot; &lt;&lt; Counter::N &lt;&lt; endl;\r\n    return 0;\r\n}\r\n<\/pre>\n<p>The output shows that <code>unique_ptr<\/code> <strong>just works<\/strong> and properly destroys the object when being assigned a new value:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n{ Enter CorrectReassignment\r\n(Dynamic allocation)\r\nMyClass:Attempt-0\r\n(Dynamic allocation)\r\nMyClass:Attempt-1\r\n~MyClass:Attempt-0\r\n(Dynamic deallocation)\r\nI have a valid pointer Attempt-1\r\n~MyClass:Attempt-1\r\n(Dynamic deallocation)\r\n} Leave CorrectReassignment\r\nFinal count: 0\r\n<\/pre>\n<p>That just about covers the basics. In the next post, I&#8217;ll show some more complex memory management situations for which the above solutions won&#8217;t suffice.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>There are many tools and techniques out there to help detect memory leaks. For instance, you can monitor performance counters for unexpected memory growth. Once a leak is suspected, UMDH might be able to help you pinpoint the culprit. However,&hellip; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[91,101],"tags":[],"class_list":["post-2051","post","type-post","status-publish","format-standard","hentry","category-design","category-native"],"_links":{"self":[{"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/posts\/2051","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2051"}],"version-history":[{"count":0,"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/posts\/2051\/revisions"}],"wp:attachment":[{"href":"http:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2051"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2051"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2051"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}