反序列化构造层次 [英] Deserializing constructor hierarchy

查看:157
本文介绍了反序列化构造层次的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

(这个问题是非常相似的<一href=\"http://stackoverflow.com/questions/35722135/deserializing-construtor-doesnt-read-data-correctly\">this 之一,但是这一次我打电话了反序列化中的儿童初始化列表构造函数)。

在其中儿童没有增加任何新数据序列化的情况下,没有默认构造函数中,我希望能够序列化对象直接以及在儿童,并没有孩子,也没有家长有默认的构造函数,这似乎是我们应该在初始化列表中使用以下模式,那里的孩子反序列化构造函数初始化父(也使用其反序列化的构造函数):

 的#include&LT;升压/存档/ text_oarchive.hpp&GT;
#包括LT&;升压/存档/ text_iarchive.hpp&GT;#包括LT&;&的fstream GT;父类
{
上市:
    双mParentData;    家长(常量双倍数据):mParentData(数据){}    模板&LT; typename的TArchive&GT;
    家长(TArchive&安培;存档)
    {
        归档&GT;&GT; *这个;
    }    模板&LT;类TArchive&GT;
    无效连载(TArchive&安培;归档,const的无符号整型版)
    {
        归档和放大器; mParentData;
    }
};儿童类:公共父
{
上市:    儿童(常量双倍数据):父(数据){}    模板&LT; typename的TArchive&GT;
    儿童(TArchive&安培;存档):家长(存档)
    {
        //什么也不做,因为读的唯一数据是在父
    }    模板&LT;类TArchive&GT;
    无效连载(TArchive&安培;归档,const的无符号整型版)
    {
        //让家长尽其系列化
        归档和放大器;提高::系列化:: base_object&LT;家长和GT;(*此);        //闲来无事,作为唯一的数据读/写在家长
    }
};诠释的main()
{
    孩童(1.2);    {
        的std ::的ofstream的OutputStream(的test.txt);
        提高::档案:: text_oarchive的outputArchive(OutputStream中);        outputArchive&LT;&LT;儿童;
        outputStream.close();
    }    {
        性病:: ifstream的InputStream的(的test.txt);
        提高::档案:: text_iarchive inputArchive(InputStream的);
        儿童childRead(inputArchive);        性病::法院LT&;&LT; childRead:&所述;&下;的std :: ENDL
                  &LT;&LT; childRead.mParentData&LT;&LT;的std :: ENDL; //输出0(预期1.2)
    }    返回0;
}

所以调用链应该(和不)如下:

输出:


  • 子::连载()

  • 父::连载()

输入:


  • 子(存档)

  • 父(存档)

  • 父::连载()

但是, mParentData childRead 0 C>,当我希望它是 1.2

任何人都可以发现这个错误吗?

----------- -----------编辑

正如@stijn指出,在孩子没有额外的数据序列化的情况下,我们可以简单地删除连载()从功能孩子完全,像这样的:

 的#include&LT;升压/存档/ text_oarchive.hpp&GT;
#包括LT&;升压/存档/ text_iarchive.hpp&GT;#包括LT&;&的fstream GT;父类
{
上市:
    双mParentData;    家长(常量双倍数据):mParentData(数据){}    模板&LT; typename的TArchive&GT;
    家长(TArchive&安培;存档)
    {
        归档&GT;&GT; *这个;
    }    模板&LT;类TArchive&GT;
    无效连载(TArchive&安培;归档,const的无符号整型版)
    {
        归档和放大器; mParentData;
    }
};儿童类:公共父
{
上市:    儿童(常量双倍数据):父(数据){}    模板&LT; typename的TArchive&GT;
    儿童(TArchive&安培;存档):家长(存档)
    {
        //什么也不做,因为读的唯一数据是在父
    }};诠释的main()
{
    孩童(1.2);    {
        的std ::的ofstream的OutputStream(的test.txt);
        提高::档案:: text_oarchive的outputArchive(OutputStream中);        outputArchive&LT;&LT;儿童;
        outputStream.close();
    }    {
        性病:: ifstream的InputStream的(的test.txt);
        提高::档案:: text_iarchive inputArchive(InputStream的);
        儿童childRead(inputArchive);        性病::法院LT&;&LT; childRead:&所述;&下;的std :: ENDL
                  &LT;&LT; childRead.mParentData&LT;&LT;的std :: ENDL; //输出0(预期1.2)
    }    返回0;
}

不过,在情况下,当这两个孩子和家长有数据序列化,他们都没有一个默认的构造函数,该模式似乎将要成为像以下,但并不完全。在儿童反序列化的构造函数,我们呼吁双方反序列化的构造,也是儿童::连载()函数,该函数调用父::连载()的功能,所以有效地将试图反序列化的两倍。这种不正确的行为表现出在这里:

 的#include&LT;升压/存档/ text_oarchive.hpp&GT;
#包括LT&;升压/存档/ text_iarchive.hpp&GT;#包括LT&;&的fstream GT;父类
{
上市:
    双mParentData;    家长(常量双倍数据):mParentData(数据){}    模板&LT; typename的TArchive&GT;
    家长(TArchive&安培;存档)
    {
        归档&GT;&GT; *这个;
    }    模板&LT;类TArchive&GT;
    无效连载(TArchive&安培;归档,const的无符号整型版)
    {
        归档和放大器; mParentData;
    }
};儿童类:公共父
{
上市:    双mChildData;    儿童(常量双parentData,常量双childData):家长(parentData),mChildData(childData){}    模板&LT; typename的TArchive&GT;
    儿童(TArchive&安培;存档):家长(存档)
    {
        归档&GT;&GT; *这个;
    }    模板&LT;类TArchive&GT;
    无效连载(TArchive&安培;归档,const的无符号整型版)
    {
        //让家长尽其系列化
        归档和放大器;提高::系列化:: base_object&LT;家长和GT;(*此);        //执行的孩子系列化
        归档和放大器; mChildData;
    }
};诠释的main()
{
    孩童(1.2,3.4);    {
        的std ::的ofstream的OutputStream(的test.txt);
        提高::档案:: text_oarchive的outputArchive(OutputStream中);        outputArchive&LT;&LT;儿童;
        outputStream.close();
    }    {
        性病:: ifstream的InputStream的(的test.txt);
        提高::档案:: text_iarchive inputArchive(InputStream的);
        儿童childRead(inputArchive);        性病::法院LT&;&LT; childRead:&所述;&下;的std :: ENDL
                  &LT;&LT; childRead.mParentData&LT;&LT;的std :: // ENDL 0.2输出(预期1.2)
                  &LT;&LT; childRead.mChildData&LT;&LT;的std :: ENDL; //输出3.4正确
    }    返回0;
}

好像在某种程度上我们需要调用不同版本的儿童::连载的()儿童反序列化的构造函数?或者设置一个标志,没有明确的反序列化儿童::连载()如果从<$称为C $ C>儿童反序列化的构造函数?

如果我们改变了儿童::连载()来下,我得到一个段错误:

 模板&LT;类TArchive&GT;
无效连载(TArchive&安培;归档,const的无符号整型版)
{
    //让家长尽其系列化
    家长::连载(存档版本);    //执行的孩子系列化
    归档和放大器; mChildData;
}


解决方案

我相信,你不需要反序列化转发给家长。
更改code到

 的#include&LT;升压/存档/ text_oarchive.hpp&GT;
#包括LT&;升压/存档/ text_iarchive.hpp&GT;#包括LT&;&的fstream GT;父类
{
上市:
  双mParentData;  家长(常量双倍数据):mParentData(数据){}  模板&LT; typename的TArchive&GT;
  家长(TArchive&安培;归档,布尔反序列化= FALSE)
  {
    如果(!反序列化)
      归档&GT;&GT; *这个;
  }  模板&LT;类TArchive&GT;
  无效连载(TArchive&安培;归档,const的无符号整型版)
  {
    归档和放大器; mParentData;
  }
};儿童类:公共父
{
上市:  儿童(常量双倍数据):父(数据){}  模板&LT; typename的TArchive&GT;
  儿童(TArchive&安培;存档):家长(存档,真)
  {
    归档&GT;&GT; *这个;
  }  模板&LT;类TArchive&GT;
  无效连载(TArchive&安培;归档,const的无符号整型版)
  {
    //让家长尽其系列化
    归档和放大器;提高::系列化:: base_object&LT;家长和GT;(*此);    //闲来无事,作为唯一的数据读/写在家长
  }
};诠释的main()
{
  {
    孩童(1.2);
    的std ::的ofstream的OutputStream(的test.txt);
    提高::档案:: text_oarchive的outputArchive(OutputStream中);    outputArchive&LT;&LT;儿童;
    outputStream.close();
  }  {
    性病:: ifstream的InputStream的(的test.txt);
    提高::档案:: text_iarchive inputArchive(InputStream的);
    儿童childRead(inputArchive);
    性病::法院LT&;&LT; childRead:&所述;&下;的std :: ENDL
      &LT;&LT; childRead.mParentData&LT;&LT;的std :: ENDL; //输出0(预期1.2)
  }  返回0;
}

我的作品。

(This question is very similar to this one, but this time I am calling the Parent deserializing constructor in the Child initialization list).

In a case where a Child adds no new data to be serialized, the Parent does not have a default constructor, I want to be able to serialize the Parent object directly as well as the Child, and neither the child nor the parent have default constructors, it seems like we should use the following pattern, where the child deserializing constructor initializes the parent (also using its deserializing constructor) in the initialization list:

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>

#include <fstream>

class Parent
{
public:
    double mParentData;

    Parent(const double data) : mParentData(data) {}

    template<typename TArchive>
    Parent(TArchive& archive)
    {
        archive >> *this;
    }

    template<class TArchive>
    void serialize(TArchive& archive, const unsigned int version)
    {
        archive & mParentData;
    }
};

class Child : public Parent
{
public:

    Child(const double data) : Parent(data) {}

    template<typename TArchive>
    Child(TArchive& archive) : Parent(archive)
    {
        // Do nothing, as the only data to read is in Parent
    }

    template<class TArchive>
    void serialize(TArchive& archive, const unsigned int version)
    {
        // Let the parent do its serialization
        archive & boost::serialization::base_object<Parent>(*this);

        // Nothing else to do, as the only data to read/write is in Parent
    }
};

int main()
{
    Child child(1.2);

    {
        std::ofstream outputStream("test.txt");
        boost::archive::text_oarchive outputArchive(outputStream);

        outputArchive << child;
        outputStream.close();
    }

    {
        std::ifstream inputStream("test.txt");
        boost::archive::text_iarchive inputArchive(inputStream);
        Child childRead(inputArchive);

        std::cout << "childRead:" << std::endl
                  << childRead.mParentData << std::endl; // Outputs 0 (expected 1.2)
    }

    return 0;
}

So the call chain should (and does) look like:

Output:

  • Child::serialize()
  • Parent::serialize()

Input:

  • Child(archive)
  • Parent(archive)
  • Parent::serialize()

However, the mParentData ends up as 0 in childRead, when I would expect it to be 1.2.

Can anyone spot the error?

----------- EDIT -----------

As pointed out by @stijn , in the case where the child has no additional data to serialize, we can simply remove the serialize() function from Child entirely, like this:

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>

#include <fstream>

class Parent
{
public:
    double mParentData;

    Parent(const double data) : mParentData(data) {}

    template<typename TArchive>
    Parent(TArchive& archive)
    {
        archive >> *this;
    }

    template<class TArchive>
    void serialize(TArchive& archive, const unsigned int version)
    {
        archive & mParentData;
    }
};

class Child : public Parent
{
public:

    Child(const double data) : Parent(data) {}

    template<typename TArchive>
    Child(TArchive& archive) : Parent(archive)
    {
        // Do nothing, as the only data to read is in Parent
    }

};

int main()
{
    Child child(1.2);

    {
        std::ofstream outputStream("test.txt");
        boost::archive::text_oarchive outputArchive(outputStream);

        outputArchive << child;
        outputStream.close();
    }

    {
        std::ifstream inputStream("test.txt");
        boost::archive::text_iarchive inputArchive(inputStream);
        Child childRead(inputArchive);

        std::cout << "childRead:" << std::endl
                  << childRead.mParentData << std::endl; // Outputs 0 (expected 1.2)
    }

    return 0;
}

However, in the case when both the child and parent have data to serialize, and they both do not have a default constructor, the pattern seems like it would need to be something like the following, but not quite. In the Child deserializing constructor, we are calling both the Parent deserializing constructor, but also the Child::serialize() function, which calls the Parent::serialize() function, so effectively the Parent would try to deserialize twice. This incorrect behavior is demonstrated here:

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>

#include <fstream>

class Parent
{
public:
    double mParentData;

    Parent(const double data) : mParentData(data) {}

    template<typename TArchive>
    Parent(TArchive& archive)
    {
        archive >> *this;
    }

    template<class TArchive>
    void serialize(TArchive& archive, const unsigned int version)
    {
        archive & mParentData;
    }
};

class Child : public Parent
{
public:

    double mChildData;

    Child(const double parentData, const double childData) : Parent(parentData), mChildData(childData) {}

    template<typename TArchive>
    Child(TArchive& archive) : Parent(archive)
    {
        archive >> *this;
    }

    template<class TArchive>
    void serialize(TArchive& archive, const unsigned int version)
    {
        // Let the parent do its serialization
        archive & boost::serialization::base_object<Parent>(*this);

        // Do the child serialization
        archive & mChildData;
    }
};

int main()
{
    Child child(1.2, 3.4);

    {
        std::ofstream outputStream("test.txt");
        boost::archive::text_oarchive outputArchive(outputStream);

        outputArchive << child;
        outputStream.close();
    }

    {
        std::ifstream inputStream("test.txt");
        boost::archive::text_iarchive inputArchive(inputStream);
        Child childRead(inputArchive);

        std::cout << "childRead:" << std::endl
                  << childRead.mParentData << std::endl  // Outputs 0.2 (expected 1.2)
                  << childRead.mChildData << std::endl; // Outputs 3.4 correctly
    }

    return 0;
}

It seems like somehow we need to call a different version of Child::serialize() from the Child deserializing constructor? Or set a flag to not explicitly deserialize Parent from Child::serialize() if it is called from the Child deserializing constructor?

If we change the Child::serialize() to the following, I get a segfault:

template<class TArchive>
void serialize(TArchive& archive, const unsigned int version)
{
    // Let the parent do its serialization
    Parent::serialize(archive, version);

    // Do the child serialization
    archive & mChildData;
}

解决方案

I believe that you don't need to forward the deserialization to the parent. Changing your code to

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>

#include <fstream>

class Parent
{
public:
  double mParentData;

  Parent(const double data) : mParentData(data) {}

  template<typename TArchive>
  Parent(TArchive& archive, bool deserialize = false)
  {
    if (!deserialize)
      archive >> *this;
  }

  template<class TArchive>
  void serialize(TArchive& archive, const unsigned int version)
  {
    archive & mParentData;
  }
};

class Child : public Parent
{
public:

  Child(const double data) : Parent(data) {}

  template<typename TArchive>
  Child(TArchive& archive) : Parent(archive, true)
  {
    archive >> *this;
  }

  template<class TArchive>
  void serialize(TArchive& archive, const unsigned int version)
  {
    // Let the parent do its serialization
    archive & boost::serialization::base_object<Parent>(*this);

    // Nothing else to do, as the only data to read/write is in Parent
  }
};

int main()
{
  {
    Child child(1.2);
    std::ofstream outputStream("test.txt");
    boost::archive::text_oarchive outputArchive(outputStream);

    outputArchive << child;
    outputStream.close();
  }

  {
    std::ifstream inputStream("test.txt");
    boost::archive::text_iarchive inputArchive(inputStream);
    Child childRead(inputArchive);


    std::cout << "childRead:" << std::endl
      << childRead.mParentData << std::endl; // Outputs 0 (expected 1.2)
  }

  return 0;
}

works for me.

这篇关于反序列化构造层次的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆