C++ vector deallocation problem

Dear experts,

In my MFC application, I have a CParagraph class which has the following member:
std::vector<CTake> m_vectorWaveTakes;

CTake is a structure that has no pointers, just integers and booleans.
When CParagraph is destroyed, I am getting an error:

Book.exe has triggered a breakpoint
The thread 'Win32 Thread' (0x12e8) has exited with code 0 (0x0).
HEAP[Book.exe]: Invalid Address specified to RtlValidateHeap( 01170000, 016428F8 )
Windows has triggered a breakpoint in Book.exe.
This may be due to a corruption of the heap, which indicates a bug in Book.exe or any of the DLLs it has loaded.
This may also be due to the user pressing F12 while Book.exe has focus.
The output window may have more diagnostic information.

The call stack shows that the problem happened in the vector destructor, but I don't know what could cause it.
Thanks.
tantormediaAsked:
Who is Participating?
 
jkrCommented:
The line

memcpy(pNewPara,pPara,sizeof(CParagraph));

seems to be the culprit. You simply can't do that with classes that hold more than POD data, and overwriting a 'vector' can definitely be the reason for the error you are seeing - better make that

*pNewPara = *pPara;

and provide an assignment operator if necessary.
0
 
jkrCommented:
Could you post the code for 'CTake'?
0
 
tantormediaAuthor Commented:
Here it is:
struct CTake
{
	CTime recordTime;
	DWORD waveLoc;
	int waveSize;
	int totalRaw;
	DWORD thisWaveTakeLoc;
	DWORD nextWaveTakeLoc;
	short waveCenter;
	short waveAveLevel;
	short waveMinNoise;
	BOOL  waveClipped;

	CTake() : recordTime(CTime::GetCurrentTime()), waveLoc(0), waveSize(0), totalRaw(0), thisWaveTakeLoc(0), nextWaveTakeLoc(0), waveCenter(0), waveAveLevel(0), waveMinNoise(0), waveClipped(FALSE){}
	CTake(CTime& time, DWORD loc, int size, int totRaw, short center, short level, short noise, BOOL clipped) : recordTime(time), waveLoc(loc), waveSize(size), totalRaw(totRaw), thisWaveTakeLoc(0), nextWaveTakeLoc(0), waveCenter(center), waveAveLevel(level), waveMinNoise(noise), waveClipped(clipped){}
};

Open in new window

0
Keep up with what's happening at Experts Exchange!

Sign up to receive Decoded, a new monthly digest with product updates, feature release info, continuing education opportunities, and more.

 
jkrCommented:
Are you performing any 'erase()' operations on the vector? Also, does this also occur if you provide a copy constructor plus an assignment operator for 'CTake'?
0
 
tantormediaAuthor Commented:
No, I am not using erase().
I added the copy constructor and an assignment operator, and still got an error

Error      7      error C2558: struct 'CTake' : no copy constructor available or copy constructor is declared 'explicit'      c:\Program Files\Microsoft Visual Studio 9.0\VC\include\vector      1211

struct CTake
{
	CTime recordTime;
	DWORD waveLoc;
	int waveSize;
	int totalRaw;
	DWORD thisWaveTakeLoc;
	DWORD nextWaveTakeLoc;
	short waveCenter;
	short waveAveLevel;
	short waveMinNoise;
	BOOL  waveClipped;

	CTake() : recordTime(CTime::GetCurrentTime()), waveLoc(0), waveSize(0), totalRaw(0), thisWaveTakeLoc(0), nextWaveTakeLoc(0), waveCenter(0), waveAveLevel(0), waveMinNoise(0), waveClipped(FALSE){}
	CTake(CTime& time, DWORD loc, int size, int totRaw, short center, short level, short noise, BOOL clipped) : recordTime(time), waveLoc(loc), waveSize(size), totalRaw(totRaw), thisWaveTakeLoc(0), nextWaveTakeLoc(0), waveCenter(center), waveAveLevel(level), waveMinNoise(noise), waveClipped(clipped){}
	CTake(CTake& orig) : recordTime(orig.recordTime), waveLoc(orig.waveLoc), waveSize(orig.waveSize), totalRaw(orig.totalRaw), thisWaveTakeLoc(orig.thisWaveTakeLoc), nextWaveTakeLoc(orig.nextWaveTakeLoc), waveCenter(orig.waveCenter), waveAveLevel(orig.waveAveLevel), waveMinNoise(orig.waveMinNoise), waveClipped(orig.waveClipped){}
	CTake& operator=(const CTake& rhs)
	{
		recordTime = rhs.recordTime; waveLoc = rhs.waveLoc; waveSize = rhs.waveSize; totalRaw = rhs.totalRaw; thisWaveTakeLoc = rhs.thisWaveTakeLoc; nextWaveTakeLoc = rhs.nextWaveTakeLoc; waveCenter = rhs.waveCenter; waveAveLevel = rhs.waveAveLevel; waveMinNoise = rhs.waveMinNoise; waveClipped = rhs.waveClipped;
		return *this;
	}
};

Open in new window

0
 
jkrCommented:
Try to make that
CTake(const CTake& orig) : recordTime(orig.recordTime), waveLoc(orig.waveLoc), waveSize(orig.waveSize), totalRaw(orig.totalRaw), thisWaveTakeLoc(orig.thisWaveTakeLoc), nextWaveTakeLoc(orig.nextWaveTakeLoc), waveCenter(orig.waveCenter), waveAveLevel(orig.waveAveLevel), waveMinNoise(orig.waveMinNoise), waveClipped(orig.waveClipped){}

Open in new window

0
 
tantormediaAuthor Commented:
I could compile it, but unfortunately the problem is still there.
0
 
jkrCommented:
Does this project consist just of an executable or are other modules involved (e.g. DLLs)? If so, are you adding elements in one module and destroying the vector in another?
0
 
tantormediaAuthor Commented:
No, everything is done in one module.
0
 
tantormediaAuthor Commented:
Here is the call stack in the debug mode:

       Book.exe!_CrtIsValidHeapPointer(const void * pUserData=0x0162d8a8)  Line 2103      C++
      Book.exe!_free_dbg_nolock(void * pUserData=0x0162d8a8, int nBlockUse=1)  Line 1317 + 0x9 bytes      C++
       Book.exe!_free_dbg(void * pUserData=0x0162d8a8, int nBlockUse=1)  Line 1258 + 0xd bytes      C++
       Book.exe!operator delete(void * p=0x0162d8a8)  Line 373 + 0xb bytes      C++
       Book.exe!std::allocator<CTake>::deallocate(CTake * _Ptr=0x0162d8a8, unsigned int __formal=3)  Line 140 + 0x9 bytes      C++
       Book.exe!std::vector<CTake,std::allocator<CTake> >::_Tidy()  Line 1134      C++
       Book.exe!std::vector<CTake,std::allocator<CTake> >::~vector<CTake,std::allocator<CTake> >()  Line 560      C++
       Book.exe!CParagraph::~CParagraph()  Line 231 + 0xfd bytes      C++


So _CrtIsValidHeapPointer() returns false, thus:
_ASSERTE(_CrtIsValidHeapPointer(pUserData)); fails.
0
 
sarabandeCommented:
those error may occur because of any other stack issue.. if for example you ever returned a pointer to a local variable and use that pointer in the calling function you may overwrite pointer values of the internal vector member. i also have seen such errors when a pointer to a local arrray was passed for use in a callback or in a asynchronously running thread. whenever the function where the local array
was defined runs out of scope the memory could be reused by any other function and such way destroy valid contents.

i would check all my functions which returm a pointer or which pass a pointer to other functions if that passing was valid. or use a purifier to check your code.

Sara



0
 
tantormediaAuthor Commented:
Thank you for your answer. What is purifier?
0
 
jkrCommented:
Hm, what does the destructor of 'CParagraph' look like?
0
 
tantormediaAuthor Commented:
     ~CParagraph() { DeleteIf(m_pText); delete m_pImg; delete [] m_pNote; };
0
 
tantormediaAuthor Commented:
This is better:
      ~CParagraph() { delete [] m_pText; m_pText = NULL; delete m_pImg; delete [] m_pNote; m_pNote = NULL; };
0
 
jkrCommented:
Could you add the declaration as well? Also, how are the pointers allocated?
0
 
tantormediaAuthor Commented:
This is the declaration. It is an inline function.
The data is read from file:
            int TextLen;
            cf->Read(&TextLen,sizeof(TextLen));

            pPara->m_pText = new char[TextLen+1];
            cf->Read(pPara->m_pText,TextLen);
            pPara->m_pText[TextLen]='\0';

                  int NoteLen;
                  cf->Read(&NoteLen, sizeof(NoteLen));

                  if(NoteLen > 0)
                  {
                        pPara->m_pNote = new char[NoteLen + 1];
                        cf->Read(pPara->m_pNote, NoteLen);
                        pPara->m_pNote[NoteLen] = '\0';
                  }

                  if(pPara->m_pImg != NULL)
                  {
                        delete(pPara->m_pImg);
                  }
                  cf->Seek(pPara->m_WaveLoc,CFile::begin);
                  char tp[4];
                  cf->Read(tp,4);
                  if(!strncmp(tp,"PNG ",4))
                  {
                        ULONGLONG s;
                        cf->Read(&s,sizeof(s));

                        CFile fTemp("temp.png", CFile::modeCreate|CFile::modeReadWrite);
                        ULONGLONG sizeWritten = 0;
                        while(s > 0)
                        {
                              ULONGLONG partSize = min(s, 1000000);
                              BYTE* pData = new BYTE[partSize];
                              cf->Read(pData, partSize);
                              fTemp.Seek(sizeWritten, CFile::begin);
                              fTemp.Write(pData, partSize);
                              delete [] pData;
                              s -= partSize;
                              sizeWritten += partSize;
                        }
                        fTemp.Close();

                        pPara->m_pImg = new CImage();
                        HRESULT res = pPara->m_pImg->Load("temp.png");
                  }

0
 
jkrCommented:
Hm, OK, this is a little too complex apparently. When you debug the destructor of 'CParagraph' and examine 'm_vectorWaveTakes', does it still contain valid entries or does it seem to be overwritten with other data?
0
 
tantormediaAuthor Commented:
At least part of the data is invalid.
This part of code may be important:

                        CParagraph * pNewPara = new CParagraph();
                        memcpy(pNewPara,pPara,sizeof(CParagraph));
 ...
                        pNewPara->m_pText = NULL;
                        pNewPara->m_pImg = NULL;
                        pNewPara->m_pNote = NULL;
                        pNewPara->m_pMyChapter = NULL;
                        delete pNewPara;

Can deleting pNewPara corrupt a vector in pPara? It is *pPara that has the problem.
0
 
tantormediaAuthor Commented:
I am getting an error:
error C2248: 'CObject::operator =' : cannot access private member declared in class 'CObject'
All members of CParagraph are public. What does it mean?
0
 
jkrCommented:
Is 'CParagraph' derived from 'CObject'?
0
 
tantormediaAuthor Commented:
Yes
0
 
jkrCommented:
Well, if it is necessary to keep that, you should give the assignment operator a try...
0
 
tantormediaAuthor Commented:
Thank you very much. Problem is solved.
0
 
sarabandeCommented:
a purifier is a tool that checks your code. it would for eXAMPLE find out if you made new but never delete a pointer or whether you write outside of array boundaries. a good tool even may have found out the error with the memcpy.

the CObject::operator=  is made private to prevent you to make copies from CObject derived classes without supplying an explicit operator= for your class. for the same reason also the copy constructor of CObject is private.

see MSDN:

The standard C++ default class assignment behavior is a member-by-member copy. The presence of this private assignment operator guarantees a compiler error message if you assign without the overridden operator. You must therefore provide an assignment operator in your derived class if you intend to assign objects of your derived class.

So when you don't have a copy constructor or operator= for your class, the compiler tries to use the baseclass functionality which fails because those functions are private to class CObject.

Sara
0
 
tantormediaAuthor Commented:
Thank you Sara.
From your phrase "a good tool even may have found out the error with the memcpy" I make a conclusion that a purifier is not a certain tool, but a general name for tools of such kind. Maybe you could give me a specific name or place where I can get it, or maybe an example how it is used?
Thanks again.
0
 
sarabandeCommented:
the most known probably is Purify from Rational. also LINT from Gimpel is widely used. unfortunately i don't know free tools but surely there are some.l

Sara
0
 
tantormediaAuthor Commented:
Thank you very much.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.