Jump to content


Template for serialization of objects


4 replies to this topic

#1 Almos

    Member

  • Members
  • PipPip
  • 99 posts

Posted 17 February 2009 - 11:03 AM

I was bored at work so I started playing with C++ binary file access and wrote a simple template for serializing structures to be written to binary file.
One obvious caveat - string fields must have fixed lengths(e.g. char name[80]). Written in NetBeans, compiled and tested with MinGW.


#include <string>

#include <fstream>

#include <vector>



using namespace std;


template<class C> class FileAccess {


private:

    string path;


public:

    FileAccess(string p){

        path = p;

    }


    void setPath(string p) {

        path = p;

    }


    bool write(C element) {


        fstream f (path.c_str(), ios::out | ios::binary);


        if(!f) return false;

        f.seekp(0, ios::end);

        f.write((char*) &element, sizeof(C));

        if(!f.good()) {

            f.close();

            return false;

        }

        else {

            f.close();

            return true;

        }

     }


    C read() {


        C buffer;

        fstream f(path.c_str(), ios::binary | ios::in);

        f.read((char*) &buffer, sizeof(C));

        return buffer;

    }


    bool serialize(vector<C> v) {

        int size = v.size();

        int i;

        fstream f(path.c_str(), ios::out | ios::binary | ios::app);

        if(!f) return false;


        f.seekg(ios::end);


        for(i=0; i<size; i++) {

            C record = v[i];

            f.write((char*) &record, sizeof(C));

        }

        

        if(!f.good()) {

            f.close();

            return false;

        }


        else {

            f.close();

            return true;

        }

    }


    vector<C> unserialize() {


        fstream f(path.c_str(), ios::in | ios::binary);

        vector<C> ret_vec;

        C record;


        while(f.read((char*) &record, sizeof(C))) {

            ret_vec.push_back(record);            

        }


        f.close();

        return ret_vec;

    }

    

    ~FileAccess() {

        

    }

};


I want to make a game as good as Elder Scrolls oblivion with no programming, just point&click. If it's not possible, I want a team of programmers I'd be able to order around. After all, I'm a n00b.

#2 .oisyn

    DevMaster Staff

  • Moderators
  • 1842 posts

Posted 17 February 2009 - 01:28 PM

So, how is this going to work for FileAccess<std::string> for example? Also, why should the serializer be responsible for knowing the path to the file. Or rather, why should it always serialize to a *file* rather than a generic stream?

I would much rather have a class that just serializes to/from a generic stream, and on which I can define my own custom serialization for custom classes. And one which can serialize to/from multiple file formats (plain old binary, XML, INI files, ...).

Maybe you should take a look at 3rd party solutions like Boost's.
C++ addict
-
Currently working on: the 3D engine for Tomb Raider.

#3 SamuraiCrow

    Senior Member

  • Members
  • PipPipPipPip
  • 459 posts

Posted 17 February 2009 - 05:04 PM

This routine is endian dependent: It assumes that the destination platform that is going to read the file is the same endianness as the one that wrote the file.

#4 Almos

    Member

  • Members
  • PipPip
  • 99 posts

Posted 18 February 2009 - 01:01 PM

Thank you for your comments. It was my first stab at serialization (actually, I wanted to check if I'll be able to store data in binary file using C++) and so I'd like to ask two questions:

1.How to handle types that don't have fixed size (such as strings)?
2.How to bypass the endianess problem?

Thanks in advance.
I want to make a game as good as Elder Scrolls oblivion with no programming, just point&click. If it's not possible, I want a team of programmers I'd be able to order around. After all, I'm a n00b.

#5 Reedbeta

    DevMaster Staff

  • Administrators
  • 5307 posts
  • LocationBellevue, WA

Posted 18 February 2009 - 05:48 PM

For strings and other arrays, a common strategy is to write the length as an integer, then the characters or elements of the array.

Another possible strategy specifically for strings is to use null termination, just like strings are stored in memory in C/C++. The caveat here is you won't be able to have embedded nulls, but most of the time you won't want them anyway.

For endianness, you just need to define the endianness of the file format, and ensure that you swap things around if you read/write it on a platform with the opposite endianness. If you only work on one platform, just define the file format endianness to match and forget about it.
reedbeta.com - developer blog, OpenGL demos, and other projects





1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users