【问题标题】:serialization of std::map which has member of boost::shared_ptr type fails具有 boost::shared_ptr 类型成员的 std::map 序列化失败
【发布时间】:2014-05-02 02:15:47
【问题描述】:

我试图在结构类型的序列化和反序列化之后比较两个映射。它给了我错误 - ““MyExample”中的错误:检查 e1_i1->second == e2_i1->second failed”

我不知道下面的代码有什么问题:

#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); 

}

我已确保包含所有头文件,但这里我没有包含所有头文件。 真的不知道上面的代码有什么问题,要么数据的设置值不正确,要么比较可能有误。

我尝试过的初始化地图的不同方法:

// 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;

谢谢,

【问题讨论】:

  • 我尝试了不同类型的地图初始化......但仍然存在上述代码中给出的问题。
  • 下面的链接也没有帮助 - stackoverflow.com/questions/1676781/…
  • 您是否使用调试器检查过地图/共享指针的内容?
  • @dutt - 是的.. 问题出在 BOOST_CHECK(e1_i1->second == e2_i1->second);两者都显示不同的地址位置而不是寻找价值..
  • 你如何从 shared_ptr 中获取值?

标签: c++ serialization boost boost-serialization


【解决方案1】:

您的比较代码应更改为

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() );
}

您还应该向A 类提供bool operator==(const A&amp; other) const,以检查A 的两个实例是否具有相同的值。

在反序列化时,要求对象分配到相同的内存地址是没有意义的,只有查看重新加载的值是否相同才有意义。

【讨论】:

  • 为A类提供布尔运算符的任何参考链接。我只是在尝试上面的代码
  • @sia:错误是e1_i1-&gt;second == e2_i1-&gt;second failed 是完全不可能的,因为我的版本中根本不存在这种比较。注意*
  • 是的,它最终失败了。如果你愿意,我也可以附上测试日志
  • 我在用我的版本替换比较版本并提供所需的A::operator== 后编译了您的代码,它按预期工作。对我来说也有点令人震惊,因为这是我第一次尝试使用 boost 编译任何东西并且工作正常(除了找到正确的链接命令有些麻烦)。
  • -你能分享你的代码版本吗..只是想和我的版本比较一下
【解决方案2】:

你很困惑。

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

相反,map 是一个有序容器,不变量恰恰是元素总是按正确的顺序

序列化没问题:Coliru 两次打印相同的数据:

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

因此,比较被打破了。修复它:

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;
}

当你不使用指针和辅助函数时,你会发现整个程序变得更小,更不容易出错。相反,请尽可能使用 **const&amp; 引用和标准习语/算法。

这是97 lines Live On Coliru 中的程序版本。

完整列表

#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";
    }
}

【讨论】:

  • 谢谢..真的有效..我错过了在示例结构中添加 bool operator== ..我只在结构 A 中添加了..
猜你喜欢
  • 1970-01-01
  • 2018-02-02
  • 1970-01-01
  • 2014-06-07
  • 1970-01-01
  • 2014-06-08
  • 1970-01-01
  • 1970-01-01
  • 2020-08-11
相关资源
最近更新 更多