michj36
michj36

Reputation: 53

Simple serialization and deserialization in C++

i need a way to serialize objects of different types (but the types deriving from the same class) and then deserialize them to the pointer of the base class, containing the deriving class. For example:

#include<iostream>
#include<fstream>
class One
{
public:
    int a;
    virtual void Func()
    {
    }
};

class One1: public One
{
    char s[128];
    void Func1(int l)
    {
        std::cout<<l<<'\n';
    }
    void Func()
    {
         Func1(156);
    }
};

int main()
{
    One* x = new One1;
    x->Func();
    char* y=(char*)x;
    delete x;
    /*std::ofstream out("test11.txt",std::ofstream::out | std::ofstream::trunc);
    out.write(y,sizeof(One1));
    out.close();
    std::ifstream in("test11.txt",std::ifstream::in);
    char* y1=new char[sizeof(One1)];
    in.read(y1,sizeof(One1));*/
    One* z=(One*)y/*1*/;
    z->Func();
    return 0;
}

This code outputs

156
156

But when I uncomment the comments (when I try to write to a file the char representation of the object and to read from this file then), the program outputs 156 and ends on segmentation fault when trying to execute z->Func();. I checked that the content of the variable y is different from y1. Why?
What is the cause of that issue and how can I address it (maybe by using some special libraries)?

Upvotes: 1

Views: 1353

Answers (1)

Paweł Stawarz
Paweł Stawarz

Reputation: 4012

1. Don't serialize derived classes by simply copying bytes

You can not simply write polymorphic objects by converting them to a byte array and then load them by a binary read. Classes with virtual functions store pointers to the implementations in a vtable. Dumping an instance of a derived class will result in dumping the pointers stored in the vtable, which - obviouly - doesn't have to be a valid pointer after you run the program once more. Accessing it after that will most probably yield a segmentation fault.

If you really want to use the easy way (directly reading and writing bytes), use POD classes.

2. Don't access invalid pointers

While the above is the most important part of the answer (because it will change your program entirely), there are also other things that need to be underlined. The command:

char* y=(char*)x;

Creates a char pointer that points to the address of x. It DOES NOT copy the object. Thus, when you later do:

delete x;

The pointer to y becomes invalid. When you later try to write that to a file:

std::ofstream out("test11.txt",std::ofstream::out | std::ofstream::trunc);
out.write(y,sizeof(One1));

You access memory that doesn't belong to you. At least not anymore, since you specificaly said you don't need it, by calling delete earlier.

Upvotes: 3

Related Questions