我正在移植现有的MFC C ++应用程序,以便对XML文件使用Boost :: Serialization。我的CDocument对象包含应用程序的所有数据。我已经将序列化函数实现为:
template<class Archive>
void CMyDoc::serialize(Archive& ar, const unsigned int version)
{
ar & BOOST_SERIALIZATION_NVP(m_Param1)
& BOOST_SERIALIZATION_NVP(m_Param2);
}
要捕获保存和加载事件,在CDoc * .cpp文件中我重载了基类函数OnOpenDocument()和OnSaveDocument()以实现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;
}
保存文档正常。问题是加载文档不起作用。 boost库似乎复制了CMyDoc对象,因为指针返回不同的地址。这意味着加载的文件未加载到当前文档中。 CDoc可以用boost覆盖自己吗?它可以与MFC CArchive。
我想过将该行表示为“可能的解决方案”,但这意味着要为CMyDoc类实现复制构造函数。这消除了boost的一个好处,即每个变量都有两行代码: ar&amp; BOOST_SERIALIZATION_NVP(m_Param1)//用于保存和加载到pDoc 2. this-&gt; m_Param1 = pDoc.m_Param1 //在CMyDoc复制构造函数中
如果我重载CMyView以捕获文件打开并保存事件,那么Doc / View架构提供的MRU列表管理将不会发生。
我确信已经完成了一百万次,但我在网上找不到任何信息。奇怪的!任何帮助非常感谢:D
更接近阅读文档,我看到Boost承认任何序列化指针都使用新关键字反序列化:“指针的序列化在库中实现,代码类似于以下代码:”
// 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();
}
文档建议在必要时重载此功能:
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);
}
但这又会导致需要实现CMyDoc拷贝构造函数。 Aaarrgghhhh !!
如果它对任何人有帮助,我得到了Robert Ramey的回复。基本上,我没有遗漏一些明显的东西:CMyDoc序列化(Archive&amp; ar,const unsigned int version)函数不是一个运行器,所以我实现了单独的boost_save和boost_load函数。我不得不重载OnOpenDocument和OnSaveDocument,例如:
BOOL CMyDoc :: OnOpenDocument(LPCTSTR lpszPathName) { 清晰();
// 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;
}
这是必要的,因为MFC CArchive拥有该文件,直到MFC Serialize函数退出,不允许boost :: serialization访问该文件。甚至在Serialize函数中调用ar.Abort()也不起作用,因为CDocument基类假定在返回基类Serialize函数时存在ar。
答案 0 :(得分:2)
使用Boost.IOStreams有一个非常巧妙的解决方案:
// We mean to not track this class, or you'll get object-tracking warnings
BOOST_CLASS_TRACKING(MyDoc, boost::serialization::track_never)
void MyDoc::Serialize(CArchive& ar)
{
namespace io = boost::iostreams;
io::file_descriptor fd(ar.GetFile()->m_hFile, io::never_close_handle);
io::stream<io::file_descriptor> file(fd);
if (ar.IsStoring())
{
boost::archive::xml_oarchive oa(file);
oa << *this;
}
else
{
boost::archive::xml_iarchive ia(file);
ia >> *this;
// then update the views...
}
}
template<class Archive>
void MyDoc::serialize(Archive & ar, unsigned version)
{
// Your Boost.Serialization code here
ar & BOOST_SERIALIZATION_NVP(member);
}
您不必费心使用OnOpenDocument / OnSaveDocument。 只需覆盖CDocument :: Serialize并将其转发到Boost.Serialization。
答案 1 :(得分:1)
重新阅读以上内容我认为这不是一个完整的答案。希望这更有帮助。
首先(重要的是,我很遗憾地发现!),将您的第一个参数设为CMyDoc
版本号变量。我有一个受保护的成员:unsigned int m_Version;
然后类构造函数是:
CMyDoc::CMyDoc(): m_Version(1) // The current file structure version
{
// construction code
}
这使您可以轻松阅读以前的文件版本。以下是四个功能,分别用于加载和保存。
加载:
BOOL CMyDoc::OnOpenDocument(LPCTSTR lpszPathName)
{
clear(); // avoid memory leaks if necessary
// Call base class function with empty local Serialize function
// to check file etc
if (!CDocument::OnOpenDocument(lpszPathName))
return FALSE;
std::string file( lpszPathName );
try {
boost_load(file);
}
catch (const boost::archive::archive_exception& ae)
{
CFrameWnd * pFrame = (CFrameWnd *)(AfxGetApp()->m_pMainWnd);
CView * pView = pFrame->GetActiveView();
ostringstream str;
str << "Problem loading file.\n"
<< "Boost reports: " << ae.what() << '\n'
<< "Possibly: " << extraArchiveWhat(ae.what())
<< std::ends;
MessageBox(pView->GetSafeHwnd(),str.str().c_str(), "MyApp", MB_OK|MB_ICONERROR);
return FALSE;
}
// If we get here we have been successful
return TRUE;
}
int CSimbaDoc::boost_load(std::string file)
{
std::ifstream ifs(file);
boost::archive::xml_iarchive ia(ifs);
int file_version; // local so as not to write over class m_Version
ia >> boost::serialization::make_nvp("m_Version", file_version)
>> BOOST_SERIALIZATION_NVP(m_Param1)
>> BOOST_SERIALIZATION_NVP(m_Param2);
if(file_version > 0) // read a variable added to class after version 0
ia >> BOOST_SERIALIZATION_NVP(m_Param3);
// and anything else you need to read
}
为了保存:
BOOL CMyDoc::OnSaveDocument(LPCTSTR lpszPathName)
{
// Call base class function with empty local Serialize function
// to check file etc
if (!CDocument::OnSaveDocument(lpszPathName))
return FALSE;
std::string file( lpszPathName );
boost_save(file);
return TRUE;
}
int CSimbaDoc::boost_save(std::string file)
{
std::ofstream ofs(file);
boost::archive::xml_oarchive oa(ofs);
oa << BOOST_SERIALIZATION_NVP(m_Version) // always save current class version
<< BOOST_SERIALIZATION_NVP(m_Param1)
<< BOOST_SERIALIZATION_NVP(m_Param2)
<< BOOST_SERIALIZATION_NVP(m_Param3);
// and whatever else
}