0

I am very new to Serialization and i am trying to use boost to serialize my data.

This is dummy code of what i intend to do.

I am using Geometry class as interface for other classes like Sphere , Rectangle etc.

The issue i have is this line "c_Restored->PrintContainer();" should call the Sphere class Virtual print function but it calls Geometry class print function which is the Parent of Sphere class.

#include "pch.h"
#include <iostream>
#include<fstream>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include "Container.h"
#include "Geometry.h"
#include "Sphere.h"

int main()
{
    const char* fileName = "saved.txt";
    Geometry* gg = new Sphere;
    Container *c = new Container("My Container", gg); // I have created a sphere object
    // save data
    {
        // Create an output archive
        std::ofstream ofs(fileName);
        boost::archive::text_oarchive ar(ofs);
        ar & c ;            
    }
    Container* c_Restored;  
    //load data
    {
        // create an input stream
        std::ifstream ifs(fileName);
        boost::archive::text_iarchive ar(ifs);
        ar & c_Restored;
    }

    Sphere* g1 = (Sphere*)c_Restored->getGeomtry();
    c_Restored->PrintContainer();
    g1->PrintGeom();  // This should call the Sphere PrintGeom function ???
    do
    {
        std::cout << '\n' << "Press a key to continue...";
    } while (std::cin.get() != '\n');
}

This is container class.

#pragma once

#include <boost/serialization/base_object.hpp>
#include <boost/serialization/split_member.hpp>
#include "Geometry.h"
class Container
{
private:
    std::string stdstrCont;
    Geometry* geom;

public:
    Container() : stdstrCont() { geom = new Geometry; }

    
    Container( std::string str , Geometry* geometry) : stdstrCont(str )
{ 
    Sphere* sph = new Sphere;
    geom = new Sphere(*sph);
}


    ~Container()
    {
        if (geom != nullptr)
            delete geom;
    }

    Geometry* getGeomtry()
    {
        return geom;
    }

    void PrintContainer()
    {
        std::cout << stdstrCont;
    }

private:

    friend class boost::serialization::access;

    void serialize(Archive& ar, const unsigned version) {
    Sphere* sss = (Sphere*)geom;
    ar & stdstrCont & sss;
}
    
};

This is Geometry Class

#pragma once

#include <string>

class Geometry
{
private:
    std::string stdstringGeom;

public:
     virtual void  PrintGeom()
    {
        std::cout << "geometry virtual function";
    }

private:
        
    friend class boost::serialization::access;


    template <typename Archive>
    void serialize(Archive& ar, const unsigned version) {
        ar & stdstringGeom;
    }
};

This is sphere class.

include "Geometry.h"

class Sphere : public Geometry
{
private:
    std::string stdstrSphere;


public:
    Sphere() : stdstrSphere( "DefaultSphere"){}
    Sphere( std::string str) : stdstrSphere(str) {}
    void PrintGeom()
    {
        std::cout << "Sphere Virtual Function" << std::endl;
    }

private:
    typedef Geometry _Super;
    friend class boost::serialization::access;


    template <typename Archive>
    void serialize(Archive& ar, const unsigned version) {
        ar & boost::serialization::base_object<_Super>(*this);
        ar & stdstrSphere;
    }

};

I feel the issue is here in container serialize function.

 template <typename Archive>
        void serialize(Archive& ar, const unsigned version) {
            
            ar & stdstrCont & geom;
        }

Though i am serializing a Sphere object but while deserializing it constructs a Geomtry object.

Community
  • 1
  • 1
  • 1
    https://www.boost.org/doc/libs/1_70_0/libs/serialization/doc/serialization.html#derivedpointers – n. m. could be an AI Sep 13 '19 at 08:08
  • 1
    At least part of the problem is that the statement `*geom = *geometry;` in your `Container` ctor is [slicing](https://stackoverflow.com/questions/274626/what-is-object-slicing) the `Sphere` passed as a parameter. Or have I missed the point? – G.M. Sep 13 '19 at 08:23
  • @G.M yes it is slicing but when i try to do this -> Sphere* sph = new Sphere; geom = new Sphere(*sph); –  Sep 13 '19 at 08:24
  • boost throws error boost::archive::archive_exception at memory location 0x000000000020F660. –  Sep 13 '19 at 08:25
  • 1
    `Container( std::string str , Geometry* geometry)` This constructor makes no sense whatsoever. What are you trying to achieve here? – n. m. could be an AI Sep 13 '19 at 08:41
  • 1
    Where is memory allocated for `Container* c_Restored;`, before `c_Restored->getGeomtry();` is invoked? When looking through boost examples, I didn't notice anything, about allocating memory for pointer variables. While stepping through your code with a debugger, did you observer, that code execution actually goes through your serialization procedures? – Algirdas Preidžius Sep 13 '19 at 08:47
  • @n.m Container can have different kind of geometry and we can use Geometry* to call virtual function Draw. –  Sep 13 '19 at 08:49
  • if (geometry->stdstrType == "Cube") { Shader shader(ResourceManager::GetShader("BasicShader")); Geom = new Sum_Cube( shader); } else if (geometry->stdstrType == "Rectangle") { Shader shader(ResourceManager::GetShader("BasicShader")); Geom = new Sum_Rectangle(shader); } –  Sep 13 '19 at 08:49
  • @Algirdas Preidzius if i change the Container Serialize function to this than i don't get any error. –  Sep 13 '19 at 08:51
  • template void serialize(Archive& ar, const unsigned version) { Sphere* sss = (Sphere*)geom; ar & stdstrCont & sss; } –  Sep 13 '19 at 08:51
  • "Container can have different kind of geometry and we can use Geometry* to call virtual function Draw". It looks like you need to purchase a more solid grasp on how objects and pointers work before delving into really complicated matters like serialisation. Set your serialisation code aside for the time being and make your Container work properly first. Have you checked that you can put a sphere in a container and then get one back without the serialisation step in between? – n. m. could be an AI Sep 13 '19 at 08:53
  • @sam That is not what I asked, since undefined behavior is undefined. And changing unrelated parts of code, might change behavior. Just to recap, I asked: "While stepping through your code with a debugger, did you observe, that code execution actually goes through your serialization procedures?" – Algirdas Preidžius Sep 13 '19 at 08:53
  • @n.m i think i have found the issue , updated in my code. –  Sep 13 '19 at 09:26
  • Your code still makes no sense. So you've shoehorned a sphere into your container (creating a memory leak in process). Can you do the same with any other type of geometry? – n. m. could be an AI Sep 13 '19 at 09:54
  • @n.m Thanks for the help i think this has become bit confusing i will post a new case with more appropriate code. –  Sep 13 '19 at 10:17

1 Answers1

0

@G.M. is right in his the comments.

Here you slice your Sphere object into a Geometry object:

    Container* c = new Container("My Container", new Sphere());
...

    Container(std::string str, Geometry* geometry) : stdstrCont(str)
    {
        geom = new Geometry;
        *geom = *geometry;
    }

And once the slicing is done it is a Geometry object, and then the correct serialization is to serialize (and restore) it as a base Geometry object. So I am fairly sure that the boost serialization works as it should, but that you simply are feeding it garbage (or at least not what you intend to feed it).

In fact this very reduced version of your main also calls the printGeom in the Geometry class (as it should, after slicing):

int main()
{
    Container* c = new Container("My Container", new Sphere);
    Sphere* g1 = (Sphere*)c->getGeomtry();
    g1->PrintGeom();
}

So my recommendation would be to fix your Container constructor (which, depending on what you want, may involve making a copy-constructor in Sphere). If this causes new problems, then write a new question here for that part specifically.

Frodyne
  • 3,547
  • 6
  • 16
  • Please have a look at the updated code for container Constructor and Serialize function and now slicing should not happen but i still get the geometry Vritual function. –  Sep 13 '19 at 09:04