Question

I'm trying to compare two maps after serialization and deserialization of struct type. It gives me error -- "error in "MyExample": check e1_i1->second == e2_i1->second failed".

I'm not able to figure out what could be wrong in below code :

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/map.hpp> 
#include <boost/serialization/shared_ptr.hpp>

struct A
{
public:
   std::string oldname;
   std::string newname;

   friend class boost::serialization::access;
      template<class Archive>
      void serialize(Archive &ar, const unsigned int version)
      {
         ar & oldname;
         ar & newname;
      }
};

struct Example
{
public:
   bool check;
   std::map<std::string,boost::shared_ptr<A>> Atype;

   private:
      friend class boost::serialization::access;
      template<class Archive>
      void serialize(Archive &ar, const unsigned int version)
      {
         ar & check;
         ar & Atype;
      }
};

void set_data(boost::shared_ptr<A> e)
{
    e->oldname="a";
    e->newname="b";
}

void set_data(Example *e)
{
   e->check=false;

   // to initialize e->Atype
   boost::shared_ptr<A> a1 (new A());
   set_data(a1);
   e->Atype.insert(std::make_pair("a",a1));
}

void compare_data(std::map<std::string,boost::shared_ptr<A>> e1,std::map<std::string,boost::shared_ptr<A>> e2)
{
   // because it is of type map, it may be not in proper order   
   typedef std::map<std::string,boost::shared_ptr<A>>::const_iterator i1;

   i1 e1_i1= e1.begin();
   i1 e2_i1 =e2.begin();

   while ( e1_i1 != e1.end() && e2_i1 != e2.end()) 
   {
      BOOST_CHECK( e1_i1->first == e2_i1->first);

      const std::string &key = e1_i1->first;
      e2_i1 =e2.find(key);
      BOOST_CHECK(e1_i1->second == e2_i1->second);

      e1_i1++;
      e2_i1++;
    }
}

void compare_data(Example *e1,Example *e2)
{
   BOOST_CHECK(e1->check == e2->check);

   // need to compare e1->Atype with e2->Atype
   compare_data(e1->Atype,e2->Atype);
}

BOOST_AUTO_TEST_CASE(MyExample)
{
   boost::archive::text_oarchive ao(std::cout);

   Example c;
   set_data(&c);

   const Example & oc=c;
   ao << oc;

   std::stringstream ss; 
   boost::archive::text_oarchive oa(ss);
   oa << oc;

   boost::archive::text_iarchive ia(ss);

   Example d;
   ia >> d;

   compare_data(&c,&d); 

}

I have made sure to include all the header files but here I have not included all. Really not sure what could be wrong in above code either setting value of data is incorrect or comparison might be wrong.

different methods for initializing the map which I tried:

// e->Atype=map_list_of ("a",a1);
// e->Atype.insert(std::make_pair("a",a1));
// e->Atype.insert(std::map<std::string,boost::shared_ptr<A>>::value_type("a",a1));
// e->Atype["a"]=a1;

Thanks,

Was it helpful?

Solution 2

You're confused.

// because it is of type map, it may be not in proper order   

On the contrary, map is an ordered container, and the invariant is precisely that elements are always in proper order.

The serialization is fine: Coliru prints the same data twice:

22 serialization::archive 10 0 0 0 0 0 1 0 0 0 1 a 0 1 4 1 0
0 1 a 1 b

22 serialization::archive 10 0 0 0 0 0 1 0 0 0 1 a 0 1 4 1 0
0 1 a 1 b

So it's the comparison that's broken. Fix it:

MapOfA mapOfA;

bool operator==(Example const& other) const {
    return (check == other.check)
        && (mapOfA.size() == other.mapOfA.size())
        && (mapOfA.end() == std::mismatch(
                mapOfA.begin(), mapOfA.end(),
                other.mapOfA.begin(),
                &ComparePair
        ).first);
}

private:
typedef MapOfA::value_type Pair;
static bool ComparePair(Pair const& a, Pair const& b) {
    bool ok = (a.first == b.first);
    if (a.second || b.second)
        ok &= (a.second && b.second) && (*a.second == *b.second);
    return ok;
}

You'll see that the whole program gets much smaller and less error-prone when you don't use pointers and helper functions all around. Instead, use **const& references and standard idioms/algorithms wherever you can.

Here's a version of your program in 97 lines Live On Coliru.

Full Listing

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/map.hpp> 
#include <boost/serialization/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <sstream>

struct A
{
    std::string oldname;
    std::string newname;

    A(std::string oldname = "", std::string newname = "") 
        : oldname(std::move(oldname)), newname(std::move(newname)) 
    { }

    bool operator==(A const& other) const {
        return (oldname == other.oldname)
            && (newname == other.newname);
    }

    friend class boost::serialization::access;
    template<class Archive>
        void serialize(Archive &ar, unsigned) {
            ar & oldname;
            ar & newname;
        }
};

struct Example
{
    typedef std::map<std::string, boost::shared_ptr<A> > MapOfA;

    bool check;
    MapOfA mapOfA;

    bool operator==(Example const& other) const {
        return (check == other.check)
            && (mapOfA.size() == other.mapOfA.size())
            && (mapOfA.end() == std::mismatch(
                    mapOfA.begin(), mapOfA.end(),
                    other.mapOfA.begin(),
                    &ComparePair
            ).first);
    }

  private:
    typedef MapOfA::value_type Pair;
    static bool ComparePair(Pair const& a, Pair const& b) {
        bool ok = (a.first == b.first);
        if (a.second || b.second)
            ok &= (a.second && b.second) && (*a.second == *b.second);
        return ok;
    }

    friend class boost::serialization::access;
    template<class Archive>
    void serialize(Archive &ar, unsigned) {
        ar & check;
        ar & mapOfA;
    }
};

template <typename T>
std::string to_string(T const& o) {
    std::stringstream ss; 
    boost::archive::text_oarchive oa(ss);
    oa << o;
    return ss.str();
}

int main()
{
    Example const data = {
        false,
        { { "ONE", boost::make_shared<A>("old one","new one") },
          { "TWO", boost::make_shared<A>("old two","new two") },
          { "TRHEE", boost::make_shared<A>("old three","new three") },
        }
    };

    std::string const original = to_string(data);

    std::cout << original << "\n";

    {
        std::stringstream ss(original); 
        boost::archive::text_iarchive ia(ss);

        Example roundtrip;
        ia >> roundtrip;

        std::string const verification = to_string(roundtrip);

        std::cout << std::boolalpha;
        std::cout << "Matching: "   << (data == roundtrip)        << "\n";
        std::cout << "Serialized: " << (verification == original) << "\n";
    }
}

OTHER TIPS

Your code for comparison should be changed to

void compare_data(const std::map<std::string,boost::shared_ptr<A>>& e1,
                  const std::map<std::string,boost::shared_ptr<A>>& e2)
{
   // because it is of type map, order IS guaranteed
   typedef std::map<std::string,boost::shared_ptr<A>>::const_iterator i1;

   i1 e1_i1= e1.begin();
   i1 e2_i1 =e2.begin();
   while ( e1_i1 != e1.end() && e2_i1 != e2.end()) 
   {
      BOOST_CHECK( e1_i1->first == e2_i1->first );
      if (e1_i1->second) {
         // Data value is present on e1, must be present on e2 too
         BOOST_CHECK( e2_i1->second );
         // The two data values must be equal
         BOOST_CHECK( *e1_i1->second == *e2_i1->second ); // Note the *
      } else {
         // Data value is not present on e1, must not be present in e2 either
         BOOST_CHECK( !e2_i1->second );
      }
      e1_i1++;
      e2_i1++;
   }
   // The iteration must terminate at the same time for e1 and e2
   // (i.e. neither of them must have extra elements in respect to the other)
   BOOST_CHECK( e1_i1 == e1.end() && e2_i1 == e2.end() );
}

You should also provide a bool operator==(const A& other) const to class A to check if two instances of A have the same value.

When deserializing it doesn't make sense to require that objects get allocated in the same memory address, it make sense only to see if the re-loaded value is the same.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top