Prev: Are cheap OEM visual studio version ok to use
Next: RS232 Interface - Serial Port - VS2008, C++
From: RB on 6 Jun 2010 09:42 Hi Joe, I think I understand what you guys are saying so I will leave it at that, albeit still leaving voids in my obsessive curiosity. However I have a question on a separate thread (same code area). I have reposted the below pertinant code for reference. Please see question at bottom. (obviously I am doing something wrong) -------------------------------------------------- class CFileHandlingDoc : public CDocument { protected: // create from serialization only CFileHandlingDoc(); DECLARE_DYNCREATE(CFileHandlingDoc) // Attributes public: CMapStringToString ExpMap1; // is serializable CMapStringToString* pExpMap1; ....... } -------------------------------------------------- In the view class data gets put in the map, here I have just plugged in some recognizable stuff, (code crunched up to save posting space) CFileHandlingDoc* DocPtr = GetDocument(); CString One, Two, Three; One = _T("WWW"); Two = _T("ZZZZ"); Three = _T("DDDD"); DocPtr->ExpMap1.SetAt(_T("a"), One); DocPtr->ExpMap1.SetAt(_T("b"), Two); DocPtr->ExpMap1.SetAt(_T("c"), Three); //so my map now has some stuff in it. ----------And the doc serialize function------------------ void CFileHandlingDoc::Serialize(CArchive& ar) { pExpMap1 = &ExpMap1; if (ar.IsStoring()) { ar << pExpMap1; } else { ar >> pExpMap1; } } =================================== When I run the above serialized code I get the below msg from my debug output window, ---I first write the file then read the file then exit app and see output--- Warning: CFile::GetStatus() returns m_attribute without high-order flags. // I always get the above warning, never been able to decipher why, (this // is still using my old VC 6 compiler, probably need to just leave it alone // and use my 2005 ide ) // But the below leak, I only get with the above serialize code. When // I change the serialize code to an alternate method (see below) I do // not get memory leaks. Detected memory leaks! Dumping objects -> strcore.cpp(118) : {333} normal block at 0x019074E0, 17 bytes long. Data: < DDDD> 01 00 00 00 04 00 00 00 04 00 00 00 44 44 44 44 strcore.cpp(118) : {332} normal block at 0x01907488, 14 bytes long. Data: < c > 01 00 00 00 01 00 00 00 01 00 00 00 63 00 strcore.cpp(118) : {331} normal block at 0x01907430, 17 bytes long. Data: < ZZZZ> 01 00 00 00 04 00 00 00 04 00 00 00 5A 5A 5A 5A strcore.cpp(118) : {330} normal block at 0x01907160, 14 bytes long. Data: < b > 01 00 00 00 01 00 00 00 01 00 00 00 62 00 strcore.cpp(118) : {328} normal block at 0x01907380, 16 bytes long. Data: < WWW > 01 00 00 00 03 00 00 00 03 00 00 00 57 57 57 00 strcore.cpp(118) : {327} normal block at 0x01907328, 14 bytes long. Data: < a > 01 00 00 00 01 00 00 00 01 00 00 00 61 00 plex.cpp(31) : {326} normal block at 0x01907240, 164 bytes long. Data: < 4s > 00 00 00 00 00 00 00 00 0C 00 00 00 34 73 90 01 map_ss.cpp(74) : {325} normal block at 0x019071B8, 68 bytes long. Data: < > 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 map_ss.cpp(394) : {322} client block at 0x019070B0, subtype 0, 28 bytes long. a CMapStringToString object at $019070B0, 28 bytes long Object dump complete. The thread 0x334 has exited with code 0 (0x0). The thread 0x134 has exited with code 0 (0x0). The thread 0xE60 has exited with code 0 (0x0). The program 'Z:\.........\FileHandling.exe' has exited with code 0 (0x0). ---------now I change "only" the serialize code (shown above) to this----- void CFileHandlingDoc::Serialize(CArchive& ar) { // Write OR ReadClass CmStS's CRuntime data ar.SerializeClass(RUNTIME_CLASS(CMapStringToString)); // Then call CmStS's serialize directly ExpMap1.Serialize(ar); if (ar.IsStoring()) { } else { } } ----first write the file then read the file then exit app then output--- // I no longer get the memory leaks. Warning: CFile::GetStatus() returns m_attribute without high-order flags. The thread 0x498 has exited with code 0 (0x0). The thread 0xEE4 has exited with code 0 (0x0). The thread 0xB04 has exited with code 0 (0x0). The program 'Z:\.........\FileHandling.exe' has exited with code 0 (0x0). -------------------------------------------------------- // When I step thru the code (not that it is relevant, just my morbid // curiosity) with this method I do not see the pOb = pClassRef->CreateObject(); // being called, in fact it seems to skip ReadObject all together and // just go from WriteClass to CRuntimeClass* PASCAL CRuntimeClass::Load(CArchive& ar, UINT* pwSchemaNum) // and loads the runtime class description, which to me (down // in my low foo bar knowledge) seems what I would think it would // be doing. // I think maybe as Goran had told me some time back that // using the SerializeClass function is the safer method to use.
From: Joseph M. Newcomer on 6 Jun 2010 13:19 See below.... On Sun, 6 Jun 2010 09:42:55 -0400, "RB" <NoMail(a)NoSpam> wrote: >Hi Joe, I think I understand what you guys are saying so I will >leave it at that, albeit still leaving voids in my obsessive curiosity. >However I have a question on a separate thread (same code area). >I have reposted the below pertinant code for reference. Please >see question at bottom. (obviously I am doing something wrong) >-------------------------------------------------- >class CFileHandlingDoc : public CDocument >{ >protected: // create from serialization only > CFileHandlingDoc(); > DECLARE_DYNCREATE(CFileHandlingDoc) > >// Attributes >public: > CMapStringToString ExpMap1; // is serializable > CMapStringToString* pExpMap1; **** Whenever I see something like this, I have to ask "why do you need the pointer variable?". In fact, I cannot imagine a single reason you would need a pointer variable that pointed to the map, if the sole purpose of this pointer variable is to hold a pointer to the map directly above it. **** > ....... >} >-------------------------------------------------- >In the view class data gets put in the map, here >I have just plugged in some recognizable stuff, >(code crunched up to save posting space) > >CFileHandlingDoc* DocPtr = GetDocument(); >CString One, Two, Three; >One = _T("WWW"); Two = _T("ZZZZ"); Three = _T("DDDD"); >DocPtr->ExpMap1.SetAt(_T("a"), One); >DocPtr->ExpMap1.SetAt(_T("b"), Two); >DocPtr->ExpMap1.SetAt(_T("c"), Three); >//so my map now has some stuff in it. >----------And the doc serialize function------------------ >void CFileHandlingDoc::Serialize(CArchive& ar) >{ > pExpMap1 = &ExpMap1; > if (ar.IsStoring()) > { > ar << pExpMap1; **** Is this the right way to serialize? I would think that this would serialize the POINTER to the map, not the map itself, which would not be useful. If you needed to serialize the pointer, you would have written ar << &ExpMap1; which means the variable, as I suspected, is completely useless. But I also suspect this is the wrong usage. I just went and read the code to CStringMapToString::Serialize and it would not be invoked if you asked it to serialize the *pointer* to the structure. **** > } > else > { > ar >> pExpMap1; > } >} >=================================== >When I run the above serialized code I get the below msg from my >debug output window, >---I first write the file then read the file then exit app and see output--- > >Warning: CFile::GetStatus() returns m_attribute without high-order flags. > >// I always get the above warning, never been able to decipher why, (this >// is still using my old VC 6 compiler, probably need to just leave it alone >// and use my 2005 ide ) > >// But the below leak, I only get with the above serialize code. When >// I change the serialize code to an alternate method (see below) I do >// not get memory leaks. **** Normally, the destructor invoked when your CDocument is destroyed should delete this. However, I've just read the code for CMapStringToString::~CMapStringToString and I don't see where this actually frees the storage. I'd have to do some experimentation to figure this out, and I don't have time to do this right now. However, I'd suggest making sure that your CDocument-derived object is, in fact, deleted before the program exits. joe **** > >Detected memory leaks! >Dumping objects -> >strcore.cpp(118) : {333} normal block at 0x019074E0, 17 bytes long. > Data: < DDDD> 01 00 00 00 04 00 00 00 04 00 00 00 44 44 44 44 >strcore.cpp(118) : {332} normal block at 0x01907488, 14 bytes long. > Data: < c > 01 00 00 00 01 00 00 00 01 00 00 00 63 00 >strcore.cpp(118) : {331} normal block at 0x01907430, 17 bytes long. > Data: < ZZZZ> 01 00 00 00 04 00 00 00 04 00 00 00 5A 5A 5A 5A >strcore.cpp(118) : {330} normal block at 0x01907160, 14 bytes long. > Data: < b > 01 00 00 00 01 00 00 00 01 00 00 00 62 00 >strcore.cpp(118) : {328} normal block at 0x01907380, 16 bytes long. > Data: < WWW > 01 00 00 00 03 00 00 00 03 00 00 00 57 57 57 00 >strcore.cpp(118) : {327} normal block at 0x01907328, 14 bytes long. > Data: < a > 01 00 00 00 01 00 00 00 01 00 00 00 61 00 >plex.cpp(31) : {326} normal block at 0x01907240, 164 bytes long. > Data: < 4s > 00 00 00 00 00 00 00 00 0C 00 00 00 34 73 90 01 >map_ss.cpp(74) : {325} normal block at 0x019071B8, 68 bytes long. > Data: < > 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 >map_ss.cpp(394) : {322} client block at 0x019070B0, subtype 0, 28 bytes long. >a CMapStringToString object at $019070B0, 28 bytes long >Object dump complete. >The thread 0x334 has exited with code 0 (0x0). >The thread 0x134 has exited with code 0 (0x0). >The thread 0xE60 has exited with code 0 (0x0). >The program 'Z:\.........\FileHandling.exe' has exited with code 0 (0x0). > >---------now I change "only" the serialize code (shown above) to this----- > >void CFileHandlingDoc::Serialize(CArchive& ar) >{ > // Write OR ReadClass CmStS's CRuntime data > ar.SerializeClass(RUNTIME_CLASS(CMapStringToString)); > > // Then call CmStS's serialize directly > ExpMap1.Serialize(ar); > > if (ar.IsStoring()) > { > } > else > { > } >} >----first write the file then read the file then exit app then output--- >// I no longer get the memory leaks. > >Warning: CFile::GetStatus() returns m_attribute without high-order flags. >The thread 0x498 has exited with code 0 (0x0). >The thread 0xEE4 has exited with code 0 (0x0). >The thread 0xB04 has exited with code 0 (0x0). >The program 'Z:\.........\FileHandling.exe' has exited with code 0 (0x0). >-------------------------------------------------------- >// When I step thru the code (not that it is relevant, just my morbid >// curiosity) with this method I do not see the > >pOb = pClassRef->CreateObject(); > >// being called, in fact it seems to skip ReadObject all together and >// just go from WriteClass to > >CRuntimeClass* PASCAL CRuntimeClass::Load(CArchive& ar, > UINT* pwSchemaNum) > >// and loads the runtime class description, which to me (down >// in my low foo bar knowledge) seems what I would think it would >// be doing. >// I think maybe as Goran had told me some time back that >// using the SerializeClass function is the safer method to use. > **** It may be. I wouldn't touch the MFC serialization for any amount of money; I consider it fragile and of very weak design. I prefer to do my own serialization as XML data, but then, I always have control of every data structure used. joe **** Joseph M. Newcomer [MVP] email: newcomer(a)flounder.com Web: http://www.flounder.com MVP Tips: http://www.flounder.com/mvp_tips.htm
From: RB on 6 Jun 2010 15:14 I' m in and out today so I will try to respond to some of this now before I head back out. >> CMapStringToString ExpMap1; // is serializable >> CMapStringToString* pExpMap1; > **** > Whenever I see something like this, I have to ask "why do you > need the pointer variable?" In fact, I cannot imagine a single reason > you would need a pointer variable that pointed to the map, if the sole > purpose of this pointer variable is to hold a pointer to the map > directly above it. > **** Well you are correct, there is no real reason and you have told me so before so I have no excuse. I should have coded this as you showed further down. > ar << &ExpMap1; > **** > Is this the right way to serialize? I would think that this would serialize > the POINTER to the map, not the map itself, which would not be useful. > If you needed to serialize the pointer, you would have written > ar << &ExpMap1; > which means the variable, as I suspected, is completely useless. But I > also suspect this is the wrong usage. I just went and read the code to > CStringMapToString::Serialize and it would not be invoked if you asked > it to serialize the *pointer* to the structure. > **** Well the way I understood it was that if the class was serializable, which CMapStringToString is, that there is an operator in the CArchive code to handle the object pointed to with it's cruntime data. It does in fact write the same data to file as the alternative method (and reads it back in) but the memory is leaking. > **** > Normally, the destructor invoked when your CDocument is destroyed > should delete this. However, I've just read the code for > CMapStringToString::~CMapStringToString and I don't see where this > actually frees the storage. I'd have to do some experimentation to figure > this out, and I don't have time to do this right now. However, I'd suggest > making sure that your CDocument-derived object is, in fact, deleted before > the program exits. joe > **** Ok, when I get in tonight I will see if I can step thru and find that. I would certainly hope so though since it was all project created when I first created the project with the whole Document template macros. >>// I think maybe as Goran had told me some time back that >>// using the SerializeClass function is the safer method to use. > **** > It may be. I wouldn't touch the MFC serialization for any amount of money; > I consider it fragile and of very weak design. I prefer to do my own > serialization as XML data, but then, I always have control of every data > structure used. joe > **** Well that is the very reason I want to understand what is going on with the MFC serialize because if I use it to store my app's file data and it someday breaks I need to know what has been written so I can code to read it back in. I have learned by experimentation and reading the Archive docs that I can readily identify every byte in a file dump and know what it is whether it be the FFFF new class tag or the schema or the filename string length or that actual CmStS value length counts, and the actual keys and values. Of course that statement is somewhat self defeative, since I guess I should about now be thinking of just writing my own serialize code from the start so I know going in what is going on. But the serialize of MFC looked so convenient I kinda wanted to utilize it but also wanted to feel confident in using it which is why I stepped thru so much of it's code. Later.......
From: RB on 6 Jun 2010 19:39 Ok I think I have found what I'm doing wrong that is causing the leak. First off I kept doing experiments, I verified that the uncommented code writes exactly the same contents to file as the embedded call of // ar.SerializeClass(RUNTIME_CLASS(CMapStringToString)); // ExpMap1.Serialize(ar); if (ar.IsStoring()) { ar << &ExpMap1; // the & works here. } else { // However I still had to use a ptr here, a & operator flags an err. ar >> pExpMap1; // &ExpMap1 here flags an error C2679 } //--------------------- And further the above uncommented method does read the data back in and can be accessed from the CmStS calls. In fact as far as the file goes both coding methods write and read the exact same file contents. BUT the ptr passing method leaks memory. And it appears to be my fault in that I did not search the docs for enough details. I did find this one example in my docs that is pertinant to the problem. Evidently if you create your object as an embedded member of the class then you must call it's serialize method with an embedded call as in SerializableClassObject.Serialize(ar); whereas objects allocated inside constructors or on the heap can be serialized with the CObject* ptr passed method. Obviously by my passing a ptr to an embedded member was throwing a wrench into the ReadObject method. --------------------------------- The following example illustrates the cases: class CMyObject : public CObject { // ...Member functions public: CMyObject() { } virtual void Serialize( CArchive& ar ) { } // Implementation protected: DECLARE_SERIAL( CMyObject ) }; class COtherObject : public CObject { // ...Member functions public: COtherObject() { } virtual void Serialize( CArchive& ar ) { } // Implementation protected: DECLARE_SERIAL( COtherObject ) }; class CCompoundObject : public CObject { // ...Member functions public: CCompoundObject(); virtual void Serialize( CArchive& ar ); // Implementation protected: CMyObject m_myob; // Embedded object //<-This is my scenario ! // !!! ***************************************** // Only difference is my CmStS Obj is in MyDocClass // !!! COtherObject* m_pOther; // Object allocated in constructor CObject* m_pObDyn; // Dynamically allocated object //..Other member data and implementation DECLARE_SERIAL( CCompoundObject ) }; IMPLEMENT_SERIAL(CMyObject,CObject,1) IMPLEMENT_SERIAL(COtherObject,CObject,1) IMPLEMENT_SERIAL(CCompoundObject,CObject,1) CCompoundObject::CCompoundObject() { m_pOther = new COtherObject; // Exact type known and object already //allocated. m_pObDyn = NULL; // Will be allocated in another member function // if needed, could be a derived class object. } void CCompoundObject::Serialize( CArchive& ar ) { CObject::Serialize( ar ); // Always call base class Serialize. // !!! ***************************************** m_myob.Serialize( ar ); // Call Serialize on embedded member. m_pOther->Serialize( ar ); // Call Serialize on objects of known exact type. // Serialize dynamic members and other raw data if ( ar.IsStoring() ) { ar << m_pObDyn; // Store other members } else { ar >> m_pObDyn; // Polymorphic reconstruction of persistent // object //load other members } } // end example
From: RB on 6 Jun 2010 19:53 Actually I got the one part of the previous post wrong For Exact types known and object already allocated on the heap in the constructor, these should be called with the embedded type call also. m_pOther = new COtherObject; // Exact type known and // object already allocated. m_pObDyn = NULL; // Will be allocated in another // member function if needed, could be a // derived class object. m_myob.Serialize( ar ); // Call Serialize on embedded member. m_pOther->Serialize( ar ); // Call Serialize on objects of known exact type. See previous post for complete example with explanations: In retrospec I don't regret running into all of this. The simple looking MyDocClass::Serialize(ar) function looked so easy. But in learning to understand it and expanding all the MFC macros has taught me more than I ever knew about the MFC structure. Sorry to waste all of you Pro's time with all my newb questions, but I have learned a great deal from you guys on this group.
First
|
Prev
|
Next
|
Last
Pages: 1 2 3 Prev: Are cheap OEM visual studio version ok to use Next: RS232 Interface - Serial Port - VS2008, C++ |