tantormedia
asked on
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.
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.
Could you post the code for 'CTake'?
ASKER
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){}
};
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'?
ASKER
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
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;
}
};
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){}
ASKER
I could compile it, but unfortunately the problem is still there.
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?
ASKER
No, everything is done in one module.
ASKER
Here is the call stack in the debug mode:
Book.exe!_CrtIsValidHeapPo inter(cons t 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<CT ake>::deal locate(CTa ke * _Ptr=0x0162d8a8, unsigned int __formal=3) Line 140 + 0x9 bytes C++
Book.exe!std::vector<CTake ,std::allo cator<CTak e> >::_Tidy() Line 1134 C++
Book.exe!std::vector<CTake ,std::allo cator<CTak e> >::~vector<CTake,std::allo cator<CTak e> >() Line 560 C++
Book.exe!CParagraph::~CPar agraph() Line 231 + 0xfd bytes C++
So _CrtIsValidHeapPointer() returns false, thus:
_ASSERTE(_CrtIsValidHeapPo inter(pUse rData)); fails.
Book.exe!_CrtIsValidHeapPo
Book.exe!_free_dbg_nolock(
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<CT
Book.exe!std::vector<CTake
Book.exe!std::vector<CTake
Book.exe!CParagraph::~CPar
So _CrtIsValidHeapPointer() returns false, thus:
_ASSERTE(_CrtIsValidHeapPo
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
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
ASKER
Thank you for your answer. What is purifier?
Hm, what does the destructor of 'CParagraph' look like?
ASKER
~CParagraph() { DeleteIf(m_pText); delete m_pImg; delete [] m_pNote; };
ASKER
This is better:
~CParagraph() { delete [] m_pText; m_pText = NULL; delete m_pImg; delete [] m_pNote; m_pNote = NULL; };
~CParagraph() { delete [] m_pText; m_pText = NULL; delete m_pImg; delete [] m_pNote; m_pNote = NULL; };
Could you add the declaration as well? Also, how are the pointers allocated?
ASKER
This is the declaration. It is an inline function.
The data is read from file:
int TextLen;
cf->Read(&TextLen,sizeof(T extLen));
pPara->m_pText = new char[TextLen+1];
cf->Read(pPara->m_pText,Te xtLen);
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::beg in);
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::m odeReadWri te);
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");
}
The data is read from file:
int TextLen;
cf->Read(&TextLen,sizeof(T
pPara->m_pText = new char[TextLen+1];
cf->Read(pPara->m_pText,Te
pPara->m_pText[TextLen]='\
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,
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::m
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.
}
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?
ASKER
At least part of the data is invalid.
This part of code may be important:
CParagraph * pNewPara = new CParagraph();
memcpy(pNewPara,pPara,size of(CParagr aph));
...
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.
This part of code may be important:
CParagraph * pNewPara = new CParagraph();
memcpy(pNewPara,pPara,size
...
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.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
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?
error C2248: 'CObject::operator =' : cannot access private member declared in class 'CObject'
All members of CParagraph are public. What does it mean?
Is 'CParagraph' derived from 'CObject'?
ASKER
Yes
Well, if it is necessary to keep that, you should give the assignment operator a try...
ASKER
Thank you very much. Problem is solved.
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:
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
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
ASKER
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.
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.
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
Sara
ASKER
Thank you very much.