反序列化构造函数无法正确读取数据

Deserializing constructor doesn't read data correctly

我正在尝试反序列化一个没有默认构造函数的对象。我已经看到您可以通过将存档传递给构造函数来做到这一点。但是,当我这样做时,它似乎没有正确读取数据?这是一个示例 - Works() 输出“1 2”(使用默认构造函数和运算符>>),但 DoesntWork() 输出“0 0”。我已经逐步完成,一切似乎都得到了适当的调用。谁能解释一下这两个函数的区别?

#include <fstream>

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

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

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

public:
    template<class TArchive>
    Point(TArchive& archive)
    {
        serialize(archive, 0);
    }

    Point(){} // Only provided to test Works()

    Point(const float x, const float y) : mX(x), mY(y) { }

    float mX = 4;
    float mY = 5;
};

void Works()
{
    std::cout << "Works():" << std::endl;
    Point p(1,2);

    std::ofstream outputStream("test.archive");
    boost::archive::text_oarchive outputArchive(outputStream);
    outputArchive << p;
    outputStream.close();

    // read from a text archive
    std::ifstream inputStream("test.archive");
    boost::archive::text_iarchive inputArchive(inputStream);
    Point pointRead;
    inputArchive >> pointRead;

    std::cout << pointRead.mX << " " << pointRead.mY << std::endl;
}

void DoesntWork()
{
    std::cout << "DoesntWork():" << std::endl;
    Point p(1,2);

    std::ofstream outputStream("test.archive");
    boost::archive::text_oarchive outputArchive(outputStream);
    outputArchive << p;
    outputStream.close();

    std::ifstream inputStream("test.archive");
    boost::archive::text_iarchive inputArchive(inputStream);
    Point pointRead(inputArchive);

    std::cout << pointRead.mX << " " << pointRead.mY << std::endl;
}

int main()
{
    Works(); // Output "1 2"
    DoesntWork(); // Output "0 0"
    return 0;
}

您不应该直接调用 serialize 方法:operator >> 对于存档来说 方式 不仅仅是调用 serialize;根据存档的类型,它首先需要加载序言等。您可以通过使用调试器单步执行或通过检查里面的内容来验证这一点 test.archive,它类似于

22 serialization::archive 12 0 0 1.000000000e+000 2.000000000e+000

所以在构建 text_iarchive 后,对 operator & 的前两次调用将碰巧看到那 2 0 而不是实际数据。

你的构造函数应该是:

template<class TArchive>
Point(TArchive& archive)
{
  archive >> *this;
}

编辑这里有一个如何使用 SFINAE 来确保复制构造函数仍然可以被调用的例子

Point( const Point& rh ) :
  mX( rh.mX ),
  mY( rh.mY )
{
}

template<class TArchive>
Point( TArchive& archive,
       std::enable_if_t< !std::is_same< TArchive, Point >::value >* = nullptr )
{
  archive >> *this;
}