C++ Boost::序列化和MFC文档/视图体系结构

C++ Boost::序列化和MFC文档/视图体系结构,c++,mfc,boost-serialization,C++,Mfc,Boost Serialization,我正在移植一个现有的MFC C++应用程序,使用XML文件的Boo::序列化。My CDocument对象包含应用程序的所有数据。我已将序列化函数实现为: template<class Archive> void CMyDoc::serialize(Archive& ar, const unsigned int version) { ar & BOOST_SERIALIZATION_NVP(m_Param1) & BOOST_SERIALIZATIO

我正在移植一个现有的MFC C++应用程序,使用XML文件的Boo::序列化。My CDocument对象包含应用程序的所有数据。我已将序列化函数实现为:

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


这是必要的,因为在MFC Serialize函数退出之前,MFC CArchive拥有该文件,因此不允许boost::serialization访问该文件。即使在Serialize函数中调用ar.Abort()也不起作用,因为CDocument基类假设在返回基类Serialize函数时ar存在。

重新阅读上面的内容,我发现这不是一个完整的答案。希望这更有帮助

首先(我遗憾地发现了这一点),将第一个参数设为
CMyDoc
版本号变量。我有一个受保护的成员:
unsigned int m_版本然后类构造函数是:

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
}
boolcmydoc::OnOpenDocument(LPCTSTR lpszPathName)
{
clear();//必要时避免内存泄漏
//使用空的本地序列化函数调用基类函数
//检查文件等
如果(!CDocument::OnOpenDocument(lpszPathName))
返回FALSE;
std::字符串文件(lpszPathName);
试一试{
boost_加载(文件);
} 
捕获(const boost::archive::archive\u异常和ae)
{
CFrameWnd*pFrame=(CFrameWnd*)(AfxGetApp()->m_pMainWnd);
CView*pView=pFrame->GetActiveView();
ostringstream str;
str BOOST_SERIALIZATION_NVP(m_Param2);
if(file_version>0)//读取在版本0之后添加到类中的变量
ia>>BOOST_序列化_NVP(m_参数3);
//还有什么你需要读的吗
}
为了节省开支:

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
}
boolcmydoc::OnSaveDocument(LPCTSTR lpszPathName)
{
//使用空的本地序列化函数调用基类函数
//检查文件等
如果(!CDocument::OnSaveDocument(lpszPathName))
返回FALSE;
std::字符串文件(lpszPathName);
boost_保存(文件);
返回TRUE;
}
int CSimbaDoc::boost_save(std::string文件)
{
std::ofs流(文件);
boost::archive::xml_oarchive oa(ofs);

oa使用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);
}
//我们的意思是不跟踪此类,否则您将收到对象跟踪警告
BOOST\u类跟踪(MyDoc,BOOST::serialization::track\u never)
void MyDoc::序列化(CArchive&ar)
{
名称空间io=boost::iostreams;
io::file_描述符fd(ar.GetFile()->m_hFile,io::never_close_handle);
io::流文件(fd);
if(ar.IsStoring())
{
boost::archive::xml\u oarchive oa(文件);
oa>*这个;
//然后更新视图。。。
}
}
模板
void MyDoc::序列化(存档&ar,未签名版本)
{
//这里是你的Boost.Serialization代码
ar&BOOST\U序列化\U NVP(成员);
}
您不必为OnPendDocument/OnSaveDocument操心。
只需覆盖CDocument::Serialize并将其转发到Boost.Serialization即可。

我一直认为这是一个非常优雅的解决方案。我只是想说声谢谢(尽管已经有一段时间了!)节点-值对是必需的:顺便说一句-boost::iostreams有什么魔力使std::iostreams不起作用?我两个都试过了,但正如您所指出的,只有boost起作用。@Colin您可能感兴趣。
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
}
// 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);
}