开发者

Writing and reading objects with virtual methods to a binary file

开发者 https://www.devze.com 2023-02-14 02:27 出处:网络
Hi I\'m currently working on a simulation program that tries to save the state (variables and objects) of the program to a binary file when requested so that it can resume the simulation if needed.

Hi I'm currently working on a simulation program that tries to save the state (variables and objects) of the program to a binary file when requested so that it can resume the simulation if needed.

Just as a note: I know that this is not compatible across different CPU architectures and that is absolutely fine!

Everything seemed to be working fine until it came to writing an object that has virtual methods to a file and then trying to reading it back.

The following code illustrates this problem:

header.hpp

using namespace std;

class parent
{
        public:
                int mValue;
                virtual string getName() =0;
                virtual size_t getSize() =0;

                parent(int value) : mValue(value)
                {

                }
};

class bob : public parent
{
        public:
                bob(int value) : parent(value)
                {

                }

        string getName();
        size_t getSize() { return sizeof(bob); }
};

string bob::getName()
{
        string name("bob");
        return name;
}

class sarah : public parent
{
        public:
                sarah(int value) : parent(value)
                {

                }

        string getName();
        size_t getSize() { return sizeof(sarah); }
};

string sarah::getName()
{
        strin开发者_高级运维g name("sarah");
        return name;
}

write.cpp

#include <iostream>
#include <fstream>
#include <string>
#include "header.hpp"

int main()
{
    sarah girl(1);
    bob boy(2);

    parent* child1 = &girl;
    parent* child2 = &boy;

    cout << "Created child called " << child1->getName() << endl;
    cout << "Created child called " << child2->getName() << endl;

    //save sarah and bob to a binary file
    ofstream file("temp.bin", ios::binary | ios::trunc);

    if(!file.is_open())
            return 1;

    //format <size><data><size><data>....
    size_t tempSize=0;

    //write child1
    tempSize = child1->getSize();
    file.write( (char*) &tempSize,sizeof(size_t));

    file.write( (char*) child1,tempSize);

    tempSize = child2->getSize();
    file.write( (char*) &tempSize,sizeof(size_t));

    file.write( (char*) child2,tempSize);

    file.close();

    return 0;
}

read.cpp

#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
#include "header.hpp"

int main()
{

    //read sarah and bob from a binary file
    ifstream file("temp.bin", ios::binary);

    //format <size><data><size><data>....
    size_t tempSize=0;

    //get size of child1
    file.read( (char*) &tempSize, sizeof(size_t));

    //allocate memory for child1
    parent* child1= (parent*) malloc(tempSize);
    //read child 1 back
    file.read( (char*) child1,tempSize);

    //get size of child2
    file.read( (char*) &tempSize, sizeof(size_t));

    //allocate memory for child2
    parent* child2= (parent*) malloc(tempSize);
    //read child 2 back
    file.read( (char*) child2,tempSize);

    file.close();

    //Using virtual methods causes SEGFAULT
    cout << "Recreated child" << child1->getName() << endl;
    cout << "Recreated child" << child2->getName() << endl;



    return 0;
}

And building and running as follows:

g++ -g write.cpp -o write ; ./write
g++ -g read.cpp -o read  ; ./read

When I step through the read program in gdb I've noticed the problem appears to be the v-table pointer. When I recreate "sarah" (child1) in the read program the v-table pointer is the one that existed for the write program, not the read program. So presumably this v-table pointer for "sarah" in the write program points to an invalid region of memory which is causing the SEGFAULT.

I have two questions:

  • Is it possible to save the v-table pointer information to the binary file in the "write" program so that my objects are perfectly recreated in the "right" program without resorting to a library such as Boost::Serialization or POST++ to handle this for me?

  • If it isn't possible ... or if it's quite complicated then I will have to add a constructor and a "saveState()" method (that can act on a ifstream and ofstream object respectively) so that each class (in this case sarah and bob) handles saving and reading it's state from a binary file. The problem with this is that I have multiple classes that are derived from the class "parent" so I would need a way for the "read" program to work out which constructor to call from reading the binary file.

    I came up with one way of working out which constructor to call. This would be

  • Giving each class that derives from "parent" a unique ID

  • In the "write" program add unique ID to the binary file
  • In the "read" program read each unique ID and then use a switch statement to call the relevant constructor.

    This isn't very elegant though as every time I add a new class that derives from "parent" I have to give it an ID and add it to the switch statement in "read". Is there a better way of doing it?

Thanks for reading, I know my post is long!


Every time your program gets compiled it puts functions in different places in memory. Also, on some operating system configurations, functions might even move around every time you restart the program. It's a security feature called address space layout randomization. If you know for sure that you will be reading and writing an object from the exact same binary, you might be able to do what you want by putting your read and write functions in the same program instead of two different ones. However, even this is fraught with the problem that if you make a change and recompile, you can no longer read your old data files anymore.

Boost::Serialization was created specifically to avoid all these issues, including I'm sure some I'm not even aware of, is heavily peer reviewed and tested, and has an extremely liberal license as a bonus. Use of such a library is not something to be "resorted" to, it's a privilege.

0

精彩评论

暂无评论...
验证码 换一张
取 消