C++ Boost::serialization : How do I archive an object in one program and restore it in another?

白昼怎懂夜的黑 提交于 2021-02-08 09:15:24

问题


I'm using Boost Serialization for saving and loading my game's overall state as well as storing map and creature data externally.

I have two programs. The first runs the game itself, creating new objects as necessary based on the data saved in the external files. It also produces savefiles of its own state. These all work so far.

The second, I am creating as a dedicated editor. I want to use it to create and manipulate said files to be used by the game program.

So I made mirror images in the second program of all the classes that require external files, but with different functions for the purposes of editing. All the data in the

void serialize(AreaArchive & aar, const unsigned int version)
{...}

part of either program's class is the same.

I use this to create the file:

areaGen.push_back(new Area("area1"));

std::string fileName;

for(std::vector<Area*>::iterator it = areaGen.begin(); it != areaGen.end(); ++it)
{
    fileName = (*it)->name + ".areabase";
    std::ofstream areafile(fileName);

    boost::archive::text_oarchive outArchive(areafile);
    outArchive << *it;
}

The file, let's say "area1.areabase" is produced perfectly AFAIK. I move it to the directory of my first program, execute the function as

bool LoadAreaState(std::string areaName, Area *target, bool baseState)
{
std::cout << "Debug: entered area loading function..." << std::endl;

std::string fileName;
if(baseState)
    fileName = areaName + ".areabase";
else
    fileName = areaName + ".areafile";

std::ifstream areafile(fileName);

...

std::cout << "Debug: file opened sucessfully..." << std::endl;

boost::archive::text_iarchive inArchive(areafile);

std::cout << "Debug: inarchive to target..." << std::endl;

inArchive >> *target; // The step at which it fails - Terminate by boost::serialization's exception

std::cout << "Debug: target Area object restored..." << std::endl;

return true;
}

And of course it doesn't work. The member object of the class in the first and second programs couldn't be the same anyway. Could it? But the serialize blocks contain the exact same type data.

I hope this example expresses what I'm trying to do. But is there a way I can make it work?

Thanks very much.


回答1:


In general, this is not supported behaviour by Boost Serialization.

For strictly trivial (POD, certainly not virtual types) you will be able to get away with things. E.g. I've in the past serialized a map<K,V> and deserialized it as a flat_map<K,V>), for trivial K and V. However, none of this is intended use for the library and you should consider the behaviour unspecified. So, unless you have verified alll code paths for yourself to be sure that what you are doing will work, and why, don't get smart with Boost Serialization.

Now, here's a trivial example that should not work:

 struct A { 
     int x;
     virtual void display() const; {}
 };

 struct B {
     int x
     virtual void display() const; {}
 };

The types will be unrelated, and the RTTI will be checked from Boost Serialization.

How To Solve This?

You could

  • Move the serializable types into a shared (static) library and use the exact same code from both programs. The problem goes away, because type information is shared
  • Use custom binary serialization
  • Use shared memory/memory mapped files instead (although this isn't trivial, so do it only if you feel confident you could do the above)

IMPORTANT Boost Serialization binary archives are not, in fact, very portable! You should look at [EOS Portable Archives](In general, this is not supported behaviour by Boost Serialization.

For strictly trivial (POD, certainly not virtual types) you will be able to get away with things. E.g. I've in the past serialized a map<K,V> and deserialized it as a flat_map<K,V>). However, none of this is intended use for the library and you should consider the behaviour unspecified. So, unless you have verified alll code paths for yourself to be sure that what you are doing will work, and why, don't get smart with Boost Serialization.

Now, here's a trivial example that should not work:

 struct A { 
     int x;
     virtual void display() const; {}
 };

 struct B {
     int x
     virtual void display() const; {}
 };

The types will be unrelated, and the RTTI will be checked from Boost Serialization.

How To Solve This?

You could

  • Move the serializable types into a shared (static) library and use the exact same code from both programs. The problem goes away, because type information is shared
  • Use custom binary serialization
  • Use shared memory/memory mapped files instead (although this isn't trivial, so do it only if you feel confident you could do the above)

IMPORTANT Boost Serialization binary archives are not, in fact, very portable! You should look at EOS Portable Archives if you want to share the archives across different machines etc. ) if you want to share the archives across different machines etc.




回答2:


A very simple example on how to print the message from an exception:

try
{
    inArchive >> *target;
}
catch (std::exception& e)
{
    std::cerr << "Exception: " << e.what() << '\n';
}


来源:https://stackoverflow.com/questions/27073936/c-boostserialization-how-do-i-archive-an-object-in-one-program-and-restore

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!