Professional C__ - Marc Gregoire [381]
Memory leaks occur when you allocate memory and neglect to release it. At first, this sounds like the result of careless programming that could easily be avoided. After all, if every new has a corresponding delete in every class you write, there should be no memory leaks, right? Actually, that’s not always true. In the following code, the Simple class is properly written to release any memory that it allocates. However, when the doSomething() function is called, the pointer is changed to another Simple object without deleting the old one. The doSomething() function doesn’t delete the old object on purpose to demonstrate memory leaks. Once you lose a pointer to an object, it’s nearly impossible to delete it.
class Simple
{
public:
Simple() { mIntPtr = new int(); }
~Simple() { delete mIntPtr; }
void setIntPtr(int inInt) { *mIntPtr = inInt; }
protected:
int* mIntPtr;
};
void doSomething(Simple*& outSimplePtr)
{
outSimplePtr = new Simple(); // BUG! Doesn't delete the original.
}
int main()
{
Simple* simplePtr = new Simple(); // Allocate a Simple object.
doSomething(simplePtr);
delete simplePtr; // Only cleans up the second object
return 0;
}
Code snippet from Leaky\Leaky.cpp
In cases like the preceding example, the memory leak probably arose from poor communication between programmers or poor documentation of code. The caller of doSomething() may not have realized that the variable was passed by reference and thus had no reason to expect that the pointer would be reassigned. If they did notice that the parameter is a non-const reference to a pointer, they may have suspected that something strange was happening, but there is no comment around doSomething() that explains this behavior.
Finding and Fixing Memory Leaks in Windows with Visual C++
Memory leaks are hard to track down because you can’t easily look at memory and see what objects are not in use and where they were originally allocated. However, there are programs that can do this for you. Memory leak detection tools range from expensive professional software packages to free downloadable tools. If you already work with Microsoft Visual C++, its debug library has built-in support for memory leak detection. This memory leak detection is not enabled by default, unless you create an MFC project. To enable it in other projects, you need to include the following three lines at the beginning of your code:
#define _CRTDBG_MAP_ALLOC
#include #include Code snippet from Leaky\Leaky MS VC++.cpp These lines should be in the exact order as shown above. Next, you need to redefine the new operator as follows: #ifdef _DEBUG #ifndef DBG_NEW #define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ ) #define new DBG_NEW #endif #endif // _DEBUG Code snippet from Leaky\Leaky MS VC++.cpp Note that this is within a “#ifdef _DEBUG” statement so the redefinition of new will only be done when compiling a debug version of your application. This is what you normally want. Release builds usually do not do any memory leak detection. The last thing you need to do is to add the following line as the first line in your main() function: _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); Code snippet from Leaky\Leaky MS VC++.cpp This tells the Visual C++ CRT (C Run Time) library to write all detected memory leaks to the debug output console when the application exits. For the previous leaky program, the debug console will contain lines similar to the following: Detected memory leaks! Dumping objects -> c:\leaky\leaky.cpp(19) : {59} normal block at 0x007E3330, 4 bytes long. Data: < > 00 00 00 00 c:\leaky\leaky.cpp(37) : {58} normal block at 0x007E32F0, 4 bytes long. Data: <03~ > 30 33 7E 00 Object dump complete. The output clearly shows in which file and on which line memory was allocated but never deallocated. The