// JP opened flex table

Click to See Complete Forum and Search --> : Memory leak in CString, CList and other classes (problem + solution)


Tom Lessing
November 13th, 2000, 07:16 AM
Every now and again I hear people growl and moan about C++ and MFC. Recently I made a stupid C++ mistake that made the CString class and template classes miss behave (according to my logic for the moment). Thought I would share it with everyone ..

Ever seen the debugger report something like this when you terminate your program?

----------------------------------------
strcore.cpp(118) : {54} normal block at 0x00301AC0, 19 bytes long.
Data: < Tomc> 01 00 00 00 06 00 00 00 06 00 00 00 54 6F 6D 63
plex.cpp(31) : {53} normal block at 0x00301B00, 124 bytes long.
Data: < 0 > 00 00 00 00 00 00 00 00 10 1B 30 00 0A 00 00 00
----------------------------------------

After a bit of an investigation one can trace the problem to CList and CString in this case very mysteriously not freeing its memory. MSDN provides no insight into the problem either.

Consider the following code snippet ...


/////////////////////////////////////////////////////////////////////////////
//
// Memory leak bug illustrated using CString classes
class CHuman
{
public:
CString m_strName;


CHuman();
~CHuman();
};
// 10/11/2000, TL: Created
CHuman::CHuman()
{

};
// 10/11/2000, TL: Created

CHuman::~CHuman()
{

};

/////////////////////////////////////////////////////////////////////////////
//
class CMan: public CHuman
{
public:
CString m_strNickName;
CList<int,int> m_lstTest;
public:

CMan();
~CMan();

};
/////////////////////////////////////////////////////////////////////////////
//
// 10/11/2000, TL: Created
CMan::CMan()
{
m_lstTest.AddHead(10);
m_lstTest.AddHead(20);

};
/////////////////////////////////////////////////////////////////////////////
//
// 10/11/2000, TL: Created
CMan::~CMan()
{

};




I used these two classes for demonstration purposes. They are simple and illustrate the behaviour nicely. To show the bug I used the following code to instatiate an object of type man called pMe. Added some stuff to it and finally deleted the object again.


//create a man (me that is)
CHuman *pMe = new CMan;


//C++ cast
//reinterpret_cast<CMan *>(pMe) ->m_strNickName = "Tomcat";

//C cast (which ever you prefer)
((CMan *)pMe) ->m_strNickName = "Tomcat";

//tell the me object my name
pMe ->m_strName = "Tom";

//delete the me object
delete pMe;

//Memory leak occurs when terminating APPLICATION !!!!

//Why does the pMe object report that tomcat is leaked but not tom?




Still wondering what the problem is?
Use the debugger and set a break point in the CMan class's destructor. Run the app again and see what happens. A quick trail and error test reveals that the CMan class's destructor never gets called. Why not? Whenever you create classes that are to be inherited ALWAYS declare your destructors to be virtual. Not doing this can easily lead to destructors not doing what it is supposed to be doing. The more classes you have and the more casting you do the better your chances of running into this kind of a problem.

I've heard some novice programmers often complain something like 'MFC is so buggy it leaks memory all over the place' or 'this class or that class doesn't work'. The bottom line is there is nothing wrong with most of the classes being it in STL or in MFC, they all work pretty well in most cases. I think this kind of bug is often blamed at bad coding on the compiler coders behalf. I hope that Microsoft and competitors will document more of this kind of strange 'buggy' behaviour. That way it is easier to solve this kind of bug that could appear to be very strange.

-----------
Assumption is the mother of all ...
Movie: Crimson Tide

Roger Allen
November 13th, 2000, 08:23 AM
Its standard procedure that if you use a base class pointer to create an inherited class object, that the base class destructor must be virtual otherwise the inherited class destructor is not called. It affects any object declared in the base class that uses deep storage, not just CStrings etc.


Good old Denzel and Gene Hackman. Good movie


Roger Allen
Roger.Allen@www.sirius-analytical.com
Ok, Points make prizes, and ratings make points.
Did I help?

Vladdy
November 22nd, 2000, 05:34 PM
Destructors obtained an ability to be virtual not a long time ago (nearly 4 years). Standard creators (among them is Bjarn Straustrup) expected virtual destructors to be very useful when playing games with virtual functions and virtual properties in general, especially when creating pointer to a base class but make point it to an inherited one. So it is not a bug, it is a feature.

I must confess that i cannot remember the case it was useful, but if it is interesting, i'll try to find one old book and try to show the example.

Faithfully, Vladdy

//JP added flex table