Serialization produces memory fault -- even in this TINY class!

[b][red]This message was edited by __c4.ep at 2003-5-20 7:37:21[/red][/b][hr]
Alright, I've tried everything over the last 5 hours, but I just can't get this code to work.

What I want to do is to serialize a class in an SDI app (created with app wizard), which holds a list of another class holding a CString object. Here's the code:

[code]
// header

class COther
{
public:
CString m_str;
};

class CData
{
public:

void Serialize( CArchive& ar )
{
m_list.Serialize( ar );
}

CList m_list;
};
[/code]

Then I instantiate CData in CSerializationDoc and add an object of COther to the list in CSerializationDoc's ctor:

[code]
CSerializationDoc::CSerializationDoc()
{
// TODO: add one-time construction code here
COther obj;
obj.m_str = "Text";
m_data.m_list.AddTail( obj );
}
[/code]

Then I finally have my Serialization func:

[code]
void CSerializationDoc::Serialize(CArchive& ar)
{
m_data.Serialize( ar );
}
[/code]

Well, if I run this app and load a document, I'm getting memory faults when exiting the app. The errors occur in CStringData::Release().
Obviously, the app tries to release a CString which already HAS been released, thus trying to delete data where nothing is anymore.

Does anyone know what the heck is going wrong here?
I have already posted two times on codeguru.com but noone can help me there. Perhaps you can?


«1

Comments

  • [b][red]This message was edited by stober at 2003-5-20 9:33:34[/red][/b][hr]
    [blue]Interesting challenge if you don't know how to do it. Just need a couple minior changes[/blue]
    [code]
    other.h

    class COther
    {
    public:
    COther();
    virtual ~COther();
    [red] virtual void Serialize(CArchive& ar);[/red]
    CString m_str;
    };

    [/code]
    [code]
    other.cpp
    void COther::Serialize(CArchive& ar)
    {
    if(ar.IsStoring())
    ar.WriteString(m_str);
    else
    ar.ReadString(m_str);

    }
    [/code]
    [code]
    MyDoc.cpp

    template <> void AFXAPI SerializeElements ( CArchive& ar, COther* pNewOther, int nCount )
    {
    for ( int i = 0; i < nCount; i++, pNewOther++ )
    {
    // Serialize each COther object
    pNewOther->Serialize( ar );
    }
    }

    [/code]


  • : [blue]Interesting challenge if you don't know how to do it. Just need a couple minior changes[/blue]

    First of all, thanks for your quick answer, I'll try this out immediately.

    But frankly I still don't understand [b]why[/b] the error occured. Could you explain what exactly went wrong there? I racked my brain on this one the whole day and I still don't get why it didn't work.

    Thanks in advance.
  • : : [blue]Interesting challenge if you don't know how to do it. Just need a couple minior changes[/blue]
    :
    : First of all, thanks for your quick answer, I'll try this out immediately.
    :
    : But frankly I still don't understand [b]why[/b] the error occured. Could you explain what exactly went wrong there? I racked my brain on this one the whole day and I still don't get why it didn't work.
    :
    : Thanks in advance.
    :
    [blue]I suspect it was because the template class didn't know how to serialize that COther class. You have to tell it how with the SerialzeObjects() template I added to the document class. After I added that, all the problems disappeared.[/blue]

  • : [blue]I suspect it was because the template class didn't know how to serialize that COther class. You have to tell it how with the SerialzeObjects() template I added to the document class. After I added that, all the problems disappeared.[/blue]
    :
    Well, thanks a ton :)

  • Oh one more question real quick:

    When exactly do I have to use the DECLARE_SERIAL/IMPLEMENT_SERIAL macros? Actually my first thought was that I have to make my COther class known to the Serialization system using those macros.

    But obviously it works without them. *confused*

  • : Oh one more question real quick:
    :
    : When exactly do I have to use the DECLARE_SERIAL/IMPLEMENT_SERIAL macros? Actually my first thought was that I have to make my COther class known to the Serialization system using those macros.
    :
    : But obviously it works without them. *confused*
    :
    :
    [blue]In your case, it doesn't matter whether you use it or not. If you want to use it for some other reason, then CObject (or some other class derived from CObject) needs to be COther's base class.

    The macros are used when the type of object in the file is unknown until runtime. The file contains information about the class that was previously written there during serialzation using the << and >> CArchive operators. You don't need this feature because you know exactly what class the data in the file belongs to and because the CList class allocates memory for them before it calls COther class's serialize function.

    Clear as mud?
    [/blue]
  • : Clear as mud?

    Somewhat yeah. Sounds like a RTTI mechanism. Although RTTI is still a big [b]?[/b] for me, I think I basically got what you mean. :)
  • I'm currently trying to implement your solution but I'm still having problems:

    If I define that function template, the compiler tells me that SerializeElements has already been defined in another file:

    [i]SWGCB error LNK2005: "void __stdcall SerializeElements(class CArchive &,class CSkillMod *,int)" ([email protected]@[email protected]@[email protected]@[email protected]) already defined in Character.obj[/i]

    The function is placed in my Document Class' cpp file.
  • : I'm currently trying to implement your solution but I'm still having problems:
    :
    : If I define that function template, the compiler tells me that SerializeElements has already been defined in another file:
    :
    : [i]SWGCB error LNK2005: "void __stdcall SerializeElements(class CArchive &,class CSkillMod *,int)" ([email protected]@[email protected]@[email protected]@[email protected]) already defined in Character.obj[/i]
    :
    : The function is placed in my Document Class' cpp file.
    :
    [blue]I had a similary problem in the example I gave you earlier. So I just moved that function to the top of the file that the compiler complained about and it fixed it. You will probably have to do the same. Move the function to the top of Character.cpp.[/blue]
  • Now I'm getting the following error (it's the same I described in the email, don't know if you've already read it, I've sent it through this board):

    error C2908:
    explicit specialization; 'void SerializeElements(CArchive &,CSkill *,INT_PTR)' has already been instantiated from the primary template
  • : Now I'm getting the following error (it's the same I described in the email, don't know if you've already read it, I've sent it through this board):
    :
    : error C2908:
    : explicit specialization; 'void SerializeElements(CArchive &,CSkill *,INT_PTR)' has already been instantiated from the primary template
    :
    [blue]I can't access my personal e-mail account from where I am at.[/code]
  • [b][red]This message was edited by __c4.ep at 2003-5-21 9:12:25[/red][/b][hr]
    I fixed that error (had to define the SerializeElements() function BEFORE any header includes occured).

    But now guess what... I'm still getting those memory faults. It's a vicious circle, I can tell you. :(

    Oh and:
    Does it make a difference if I use CArchive::WriteString and CArchive::ReadString or << and >> to store/read CStrings. Perhaps that's the source of all evil, I don't know. I always used the streaming operators because the MSDN said that they were overloaded for CString objects. But when I have a look at the strings read out from the archive after opening a file I doubt that... They are totally crippled. Seems that even the saving doesn't work properly.


  • [b][red]This message was edited by __c4.ep at 2003-5-21 9:18:52[/red][/b][hr]
    Hah, I have found something out:

    The Serialize() method of the class which objects are stored in said list is never called! That means the CList::Serialize() method is still making bit-wise copies of the contained objects which would explain that I still have memory faults.

    But this would mean as well that the definition of that template function is worthless, or at least the CList simply ignores it, because I call the serialization method of the stored object inside this function (as you told me).

    This is getting weirder with every minute I work on this problem.


  • compile for debug and put a breakpoint in that SerializeObject() function to see if its actualy getting called or not. I think the parameters to it have to be identical to how you created the CList object in the first place. Of course the alternative is not to use the Serialize method of that CList template, but to do your own thing.
  • : Oh one more question real quick:
    :
    : When exactly do I have to use the DECLARE_SERIAL/IMPLEMENT_SERIAL macros? Actually my first thought was that I have to make my COther class known to the Serialization system using those macros.
    :
    : But obviously it works without them. *confused*
    :
    :
    If you want to use the macros, the following should work....

    The first thing you need to do is derive all of your classes from CObject. Then you implement the Serializable function for in each class.
    (BTW: I gave up trying to use CList and replaced it with std::list)

    [code]
    class COther: public CObject
    {
    DECLARE_SERIAL(COther)
    public:
    COther(){}
    COther(const COther &rhs)
    {
    m_str = rhs.m_str;
    }
    CString m_str;
    COther & operator = (COther &rhs)
    {
    m_str = rhs.m_str;
    return *this;
    }
    void Serialize(CArchive &ar)
    {
    CObject::Serialize (ar);
    if (ar.IsStoring ())
    ar << m_str;
    else // Loading, not storing
    ar >> m_str;
    }

    };

    class CData : public CObject
    {
    DECLARE_SERIAL(CData)
    public:
    CData();
    virtual ~CData();
    list m_list;
    void Serialize(CArchive &ar)
    {
    CObject::Serialize (ar);
    if (ar.IsStoring ())
    {
    for(list::iterator i = m_list.begin(); i != m_list.end(); ++i)
    {
    i->Serialize(ar);
    }
    }

    else
    {// Loading, not storing
    for(list::iterator i = m_list.begin(); i != m_list.end(); ++i)
    {
    i->Serialize(ar);
    }
    }
    }

    };
    [/code]

    In your Data.cpp file you need to include

    [code]
    IMPLEMENT_SERIAL(COther, CObject, 1)
    IMPLEMENT_SERIAL(CData, CObject, 1)
    [/code]

    And finally in your doc

    [code]
    CSerializationDoc::CSerializationDoc()
    {
    // TODO: add one-time construction code here
    COther obj;
    obj.m_str = "Hello World";
    p = new CData;
    p->m_list.push_back(obj);
    }

    void CSerializationDoc::Serialize(CArchive& ar)
    {
    if (ar.IsStoring())
    {
    // TODO: add storing code here
    p->Serialize(ar);
    AfxMessageBox("Saving");
    }
    else
    {
    // TODO: add loading code here
    p->Serialize(ar);
    // Following for testing only//
    CString temp;
    list::iterator i = p->m_list.begin();
    temp = i->m_str;
    AfxMessageBox("Retrieving");
    AfxMessageBox(temp);

    }
    }
    [/code]

    Have to admit the Prosise book was a BIG help
Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Categories