Click here to Skip to main content
15,920,383 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I asked this on Stack Overflow but didn't get any answers - I hope you don't mind me asking here also.

I'm porting an existing MFC C++ application to use Boost::Serialization for XML files. My CDocument object contains all the data for the app. I've implemented the serialize function as:

template<class Archive>
void CMyDoc::serialize(Archive& ar, const unsigned int version)
{
ar  & BOOST_SERIALIZATION_NVP(m_Param1)
    & BOOST_SERIALIZATION_NVP(m_Param2);
}


To capture the save and load events, in the CDoc *.cpp file I have overloaded the base class functions OnOpenDocument() and OnSaveDocument() to implement Boost::Serialization:

BOOL CMyDoc::OnOpenDocument(LPCTSTR lpszPathName)
{
clear();    // clear current params

//if (!CDocument::OnOpenDocument(lpszPathName)) // Old MFC serialize code
//  return FALSE;

CEvolveTrafficDoc* pDoc = this; // pointers the same here
std::ifstream ifs(lpszPathName);
boost::archive::xml_iarchive ia(ifs);
ia >> boost::serialization::make_nvp("MyDoc",pDoc); // pointer changes here
// *this = *pDoc; // POSSIBLE solution with CMyDoc copy constructor implemented

return TRUE;
}

BOOL CMyDoc::OnSaveDocument(LPCTSTR lpszPathName)
{
//if (!CDocument::OnSaveDocument(lpszPathName)) // Old MFC serialize code
//  return FALSE;

std::ofstream ofs(lpszPathName);
boost::archive::xml_oarchive oa(ofs);
oa << boost::serialization::make_nvp("MyDoc",this);

return TRUE;
}


Saving a document works fine. The problem is that loading a document doesn't work. The boost library seems to copy the CMyDoc object because the pointer comes back a different address. This means that the loaded file isn't loaded into the current document. Can a CDoc overwrite itself with boost? It can with MFC CArchive.

I thought about having the line indicated as "POSSIBLE solution", but this would mean implementing the copy constructor for the CMyDoc class. This removes one of the benefits of boost in that I would have two lines of code for each variable:
1. ar & BOOST_SERIALIZATION_NVP(m_Param1) // for saving and loading to pDoc
2. this->m_Param1 = pDoc.m_Param1 // in CMyDoc copy constructor

If I overload the CMyView to capture the file open and save events, the MRU list management offered by the Doc/View architecture won't happen.

I'm sure this has been done a million times, but I can't find any information online. Weird! Any help much appreciated :D

EDIT:
Reading the documentation closer, I see that Boost acknowledges that any serialized pointer is deserialized with a new keyword: "Serialization of pointers is implemented in the library with code similar to the following:"

// load data required for construction and invoke constructor in place
template<class Archive, class T>
inline void load_construct_data(
Archive & ar, T * t, const unsigned int file_version
){
// default just uses the default constructor to initialize
// previously allocated memory. 
::new(t)T();
}


The documentation recommends overloading this function if necessary:

template<class Archive>
inline void load_construct_data(
Archive & ar, my_class * t, const unsigned int file_version
){
// retrieve data from archive required to construct new instance
int attribute;
ar >> attribute;
// invoke inplace constructor to initialize instance of my_class
::new(t)my_class(attribute);
}


But this would again result in needed to implement a CMyDoc copy constructor. Aaarrgghhhh!!
Posted
Updated 3-Jul-11 6:21am
v2

1 solution

In case it helps anyone, I had a reply from Robert Ramey about this. Basically, I wasn't missing something obvious: the CMyDoc serialize(Archive& ar, const unsigned int version) function wasn't a runner, so I implemented separate boost_save and boost_load functions. I had to overload the OnOpenDocument and OnSaveDocument, for example:

BOOL CMyDoc::OnOpenDocument(LPCTSTR lpszPathName)
{
    clear();
   
    // Call base class function with empty local Serialize function
    // to check file exists etc
    if (!CDocument::OnOpenDocument(lpszPathName))
        return FALSE;

    std::string file( lpszPathName );
    boost_load(file);
    return TRUE;
}


This is necessary since the MFC CArchive owns the file until the MFC Serialize function exits, disallowing boost::serialization to access the file. Even calling ar.Abort() in the Serialize functions doesn't work because the CDocument base class assumes the ar exists on returning to the base class Serialize function.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900