CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 8 of 8
  1. #1
    Join Date
    Nov 2002
    Location
    Scotland
    Posts
    39

    Memory Leaks deleting ptr to TCHAR[]'s inside CPtrArray

    Hi

    I'm trying to store many TCHAR strings as dynamically created on the heap as pointers inside a CArray (CTypedPtrArray<CPtrArray,TCHAR*>).

    I made a small class to wrap it all as below. However when I come to clean up after deleting the class it reports each string as a leak, even though I did the delete on it.

    Any Ideas?
    Header
    Code:
    class CTextContainerArray : public  CTypedPtrArray<CPtrArray,TCHAR*>  
    {
    // Construction
    public:
       CTextContainerArray();
       ~CTextContainerArray();
       void AddString(TCHAR* pStr,int len);
    };
    Body
    Code:
    CTextContainerArray::CTextContainerArray(){}
    
    CTextContainerArray::~CTextContainerArray()
    {
    	TCHAR* pText;
    	for (int j =0; j < GetSize(); j++)
    	{
    		pText = (TCHAR*)GetAt(j);
    		if(pText) 
    		{
    			delete [] pText;
    		}
    	}
    	RemoveAll();
    }
    
    void CTextContainerArray::AddString(TCHAR* pStr,int len)
    {
    	TCHAR* newstr = NULL;
    	if ((len > 0) && pStr)
    	{
    		newstr = new TCHAR[len];
    		if (newstr)	
    		{
    			wcscpy(newstr,pStr);
    		}
    	}
    	Add(newstr);
    }
    Sample of Memory leak output:

    {9904} normal block at 0x011AD6E8, 64 bytes long.
    Data: < C| > B8 AE 43 7C 17 00 00 00 17 00 00 00 01 00 00 00
    {9903} normal block at 0x011AD688, 30 bytes long.
    Data: < C| > B8 AE 43 7C 06 00 00 00 06 00 00 00 01 00 00 00
    {9902} normal block at 0x011AD608, 64 bytes long.
    Data: < C| > B8 AE 43 7C 17 00 00 00 17 00 00 00 01 00 00 00
    {9901} normal block at 0x011AD5A8, 30 bytes long.


    Something else that was quite interesting, is that previous to the version above. I allocated the memory for the string separately, copied the string into the new memory location given by new. Then used the CArray->Add member to simply add the pointer to the allocated string. This also leaked. But the leak was the actual string memory location. IE you could see the text in the leak print out!

    Do I need to write my own heap manager functions and use my own heap area? Or am I doing something really silly?

    Also does it matter that this class is created in a worker thread of a CDoculent? The class is then added to another CArray. I haven't had any problems with these.

  2. #2
    Join Date
    Aug 2000
    Location
    West Virginia
    Posts
    7,725
    When you call AddString(), what do you pass as the
    length ? the wcslen() or wcslen() + 1 ? i.e. In AddString()
    are you allocating space for the trailing NULL ?

  3. #3
    Join Date
    Dec 2002
    Posts
    1,050
    Also does it matter that this class is created in a worker thread of a CDoculent?
    Sure ! If you want to see if the class is causing a leak, drop it
    into a console, or some similar simple app, and see if it leaks
    there. I'll bet this one doesn't ( I checked ). Just because the
    output window shows a leak that doesn't mean theres a leak -
    just that at that time there seems to be.

    And why pass in the len to AddString() - can't AddString() figure
    that out itself leaving the caller to do less work ?

  4. #4
    Join Date
    Sep 1999
    Location
    Colorado, USA
    Posts
    1,002
    I don't understand why you wouldn't use an array that has been designed to handle string arrays, CStringArray.

    An alternative would be vector<string>

    Steve

  5. #5
    Join Date
    Nov 2002
    Location
    Scotland
    Posts
    39
    Thanks for the answers guys.

    Philip:

    I'm using wcslen(). So I think your hunch must be correct. I'll check in a minute or two.

    mdmd:

    The only excuse I can think of for not noticing that I don't need to pass in the length of the string is that maybe one day I'll need a class that can handle both strings, and arrays of unsigned shorts. Until I remove it a few minutes. I'll stand by it.

    Steve:

    The reason I was trying this is to speed up the loading of my program. The CStrings I feel are just an uncessesary overhead. The code runs on XP, and also windows CE 3.0. The CE machine is only 166Mhz! After loading a few thousand small CStrings from a text file a lot of time has gone past.

    However, the main reason I'm reducing the CString usage is becuase I think my program is suffering from memory fragmentation caused by the constant resizing of the CStrings. It's very noticeable on the wince machine after about 10 or so hours continuous running. The strings loaded into this class are never modified, so why even need them in a CString? In other places I'm trying to use fixed length buffers instead of CStrings, and I'll maybe port the CStr class to unicode that's around in the projects somewhere (or is that codeproject?). It has it's own heap memory management apparently.

    Oh and as my class isn't working it's currently commented out, and I've typedef'd CTextContainer to a CStringArray, and a small change where I called AddString().

    vector<string>? STL isn't supported on Wince 3.0

  6. #6
    Join Date
    Nov 2002
    Location
    Scotland
    Posts
    39
    Ok, I've just modified the appropriate code and re-compiled.

    There is a massive difference in the ammount of memory leaks. Out of about 6000 strings for some reason about 6 leaked. Luckily I've also found that there's a typo in the ini file, causing the instance of the textcontainer class to have been overwriten in his parent array with another array. So the orphaned class never got destroyed. Simple to prevent next time.

    I'm sure even in XP on a 2Ghz processor there is a slight speed improvent using the code below rather than CStringsArray. I might even add some performance counters to check.

    Thanks again for the help (especially Philip). I would probably banged my head against the wall for days with this one. Even though the program can't be closed, as you have to hard reset the device. I would have gone mad with all those leaks hiding in the program somewhere!

    fixed code

    Code:
    void CTextContainerArray::AddString(TCHAR* pStr)
    {
    	TCHAR* newstr = NULL;
    	int len = 0;
    	if (pStr)
    	{
    		len = wcslen(pStr) + 1;
    		newstr = new TCHAR[len];
    		if (newstr)	
    		{
    			wcscpy(newstr,pStr);
    		}
    	}
    	Add(newstr);
    }

    PS: There is still one other memleak. It's very interesting. It only gets registered by Visual Studio 2003. If you double click on the line in the output window Visual studio crashes. hehe

    Looks like this:
    Detected memory leaks!
    Dumping objects ->
    thrdcore.cpp(311) : {230} client block at 0x00D4FC40, subtype c0, 68 bytes long.
    a CWinThread object at $00D4FC40, 68 bytes long

    What's 68 bytes to friends anyway?

  7. #7
    Join Date
    Jan 2002
    Location
    Scaro, UK
    Posts
    5,940
    Memory leaks should always be eliminated in my opinion - no matter how small.

    Consider that for a particular operation only 2 bytes are leaked. However, if this operation is done 100 times a second that means it is leaking 200 bytes per second ! Eventually your program will terminate because of this.

    So I would seriously try to eliminate the leak.

    Oh and by the way it seems that you're not deleting your thread correctly. Are you using manual or auto delete of the thread ? There's a member in the CWinThread class called m_bAutoDelete or something which tells it whether to delete itself when it exits.

    Set this in the constructor to being 1 and all should be fine then.

    Darwen.
    Last edited by darwen; April 11th, 2004 at 01:02 AM.
    www.pinvoker.com - PInvoker - the .NET PInvoke Interface Exporter for C++ Dlls.

  8. #8
    Join Date
    Sep 1999
    Location
    Colorado, USA
    Posts
    1,002
    Interesting problem and you seem to have solved most of your difficulty.
    If none of these strings are modified, you might try another approach. Depending on what your program does with the data, this may or may not be practical. Read in all the "strings" at once as one memory block. Before you read in the strings block, read in an array of indexes which are a map into the strings block. The last value in the index array is the length of the last "string".

    Steve

    Steve

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured