Re: CreateObject confused
On Jun 5, 4:14 pm, "RB" <NoMail@NoSpam> wrote:
........................ For example, the MFC framework (which was compi=
led
in 2008 without knowing your class name) creates your CFileHandlingDoc =
at startup, but it does so without a
CFileHandlingDoc* p = new CFileHandlingDoc();
statement. The CRuntimeClass provides the needed data about the obje=
ct.
The same ability is used by CArchive to create objects from the file st=
ream. Instead of having a 'new' statement for each possible
class it uses CreateObject to create all objects. Scott McPhillips [VC+=
+ MVP]
Ok, that verbalizes more clearly, but if I may be so curious why does
my CMapStringToString Object which is already in existence need
CreateObject to create a object to receive my serialized read ?
It appears the WriteClass and ReadClass (called by WriteObject or
ReadObject ) has no problem fetching the CmStS's Cruntime data
from my file. So after that, I don't see why another object needs created
before actually reading the CMap in ?
Because that's how you wrote your code (and it's wrong). The problem
is this snippet:
pExpMap1 = &ExpMap1; // 0
if (ar.IsStoring())
{
ar << pExpMap1;
}
else
{
ar >> pExpMap1;
}
0 is rather unusual and normally a mistake. In serialization, when the
object you want to serialize is "embedded" into another object (as is
the case with your ExpMap1 - it's a member of your document), you
___don't___ use operators >> and <<. (Didn't I explained this you you
earlier? Maybe explanation wasn't good enough?).
Instead, you simply do:
ExpMap1.Serialize(ar);
For ExpMap1 defined as it is, that's it. No "if (storing)", no
additional pointer, no nothing! Just call Serialize, end of.
If the object in question is something you made, and has a versionable
schema (which is the usual case), you do:
ar.SerializeClass(m_object.GetRuntimeClass()); // ^^^^
m_object.Serialize(ar);
If you hold the object in question as a pointer (on the heap), only
then you do:
if (ar.IsStoring())
ar << m_pObject;
else
ar >> m_pObject;
So... What you tried is completely wrong - you just mixed everything
in a bad way. It could be that you don't understand how objects on
heap work, it could be that you don't understand serialization, or it
could be something else, I don't know.
About why there's a call to CreateObject while loading: well, it's
there because that's how operator>>(CArchive, CObject*&) work, and you
put that call in.
Finally, files that you already saved in there are bad and when you
fix your code, you won't be able to load them. If backward-
compatibility is important (I doubt you are in that stage), then I
would do the following:
class CFileHandlingDoc
{
CFileHandlingDoc() : m_pExpMap(new CMapStringToString) {}
void DeleteContents() { delete m_pExpMap; m_pExpMap = NULL; }
CMapStringToString m_pExpMap;
// No "embedded" object anymore;
}
CFileHandlingDoc()::Serialize(...)
{
if (storing)
ar << m_pExpMap;
else
ar >> m_pExpMap;
}
IOW, since you saved your map as pointer on the heap, make it a
pointer on the heap and continue like so. That might be suboptimal
(one more heap pointer, a couple of calls to new/delete), but I will
put my hand in fire that you can't ever notice a difference.
Goran.
^^^^ (I told you already that MSDN explanation on what SerializeClass
is for, whilst correct, is also useful when serializing "embedded"
objects; if ever internal workings of MFC change so that it does
something differently, then I'll start to be wrong; but since
SerializeClass is like it is for, I dunno, 15 years, I doubt it can
ever change).