Boost binary_oarchive 不适用于动态缓冲区

问题描述 投票:0回答:1

我正在尝试使用 boost 序列化来序列化对象。如果我使用 text_archive,一切都会完美运行,我可以序列化、反序列化回来,并且一切都就位。我尝试使用二进制存档进行序列化,结果好坏参半。如果我使用连接到字符缓冲区的 boost array_sink,一切都会顺利进行。如果我更改为动态分配的缓冲区,则序列化失败,并且相应的向量留空。 我发现很多人使用带后置插入器的 iostream 的例子,但没有人遇到这样的问题。 这是一个给我错误的例子:

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

#include <boost/serialization/access.hpp>
#include <boost/serialization/shared_ptr.hpp>

#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/device/back_inserter.hpp>
#include <boost/iostreams/stream.hpp>

#include <cassert>
#include <iostream>


class MyClass
{
    public:
    MyClass(int myVar) : _myVar(myVar) {}
    MyClass() {}

    int _myVar = 0;

    friend bool operator== (const MyClass& c1, const MyClass& c2)
    {
        return c1._myVar == c2._myVar;
    }

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


int main(int, char**)
{
    std::shared_ptr<MyClass> srcPtr(new MyClass(42));
    std::shared_ptr<MyClass> dstPtr;

    std::cout << "Serialize using stringstream and text archive" << std::endl;
    std::stringstream oss;
    boost::archive::text_oarchive toa(oss);
    toa << srcPtr;

    std::cout << oss.str() << std::endl;

    std::stringstream iss(oss.str());
    boost::archive::text_iarchive tia(iss);
    tia >> dstPtr;

    assert(*srcPtr == *dstPtr);
    std::cout << "Dest var is: " << dstPtr-> _myVar << std::endl;
    dstPtr.reset();
    std::cout << "Done" << std::endl;

    //Static buffer and binary
    std::cout << "Serialize using static buffer and binary archive" << std::endl;
    char testBuffer[4096];
    boost::iostreams::stream<boost::iostreams::array_sink> static_os(testBuffer);
    boost::archive::binary_oarchive static_oa(static_os);
    static_oa << srcPtr;

    std::cout << "Static buffer, buffer size: " << static_os.tellp() << std::endl;

    boost::iostreams::stream<boost::iostreams::array_source> static_is(testBuffer);
    boost::archive::binary_iarchive static_ia(static_is);
    static_ia >> dstPtr;

    assert(*srcPtr == *dstPtr);
    std::cout << "Dest var is: " << dstPtr-> _myVar << std::endl;
    dstPtr.reset();
    std::cout << "Done" << std::endl;

    //Dynamic vector
    std::cout << "Serialize using dynamic buffer and binary archive" << std::endl;
    std::vector<char> buffer;
    boost::iostreams::stream obs(boost::iostreams::back_inserter(buffer));
    boost::archive::binary_oarchive oba(obs);
    oba << srcPtr;

    std::cout << "BufferSize: " << buffer.size() << std::endl;

    boost::iostreams::stream<boost::iostreams::array_source> ibs(buffer.data(),buffer.size());
    boost::archive::binary_iarchive iba(ibs);
    iba >> dstPtr;

    assert(*srcPtr == *dstPtr);
    std::cout << "Dest var is: " << dstPtr-> _myVar << std::endl;
    dstPtr.reset();
    std::cout << "Done" << std::endl;
}

输出是

Serialize using stringstream and text archive
22 serialization::archive 18 0 1 1 1 0
0 42
Dest var is: 42
Done
Serialize using static buffer and binary archive
Static buffer, buffer size: 60
Dest var is: 42
Done
Serialize using dynamic buffer and binary archive
BufferSize: 0
terminate called after throwing an instance of 'boost::wrapexcept<std::ios_base::failure[abi:cxx11]>'
  what():  no read access: iostream error
Aborted (core dumped)
c++ serialization boost
1个回答
0
投票

就像我之前评论的那样,这是一个陷阱。某些存档类型需要在存档析构函数中完成(例如 XML 存档)。

对于许多存档类型,简单的刷新似乎就足够了。事实上,在文本存档中,换行符通常会导致底层操作系统文本流实现的隐式刷新。

但是,为了正确起见,您需要在使用流内容之前完成存档。

这是我的简化版本,演示了所有三个:

住在Coliru

#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/access.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/device/back_inserter.hpp>
#include <boost/iostreams/stream.hpp>
#include <cassert>
#include <iostream>

struct MyClass {
    MyClass(int myVar=0) : _myVar(myVar) {}
    bool operator== (const MyClass& o) const { return _myVar == o._myVar; }

  private:
    int _myVar = 0;

    friend class boost::serialization::access;
    void serialize (auto &ar, unsigned) { ar & _myVar; }
};

namespace io = boost::iostreams;
namespace ba = boost::archive;

int main() {
    std::shared_ptr<MyClass const> srcPtr(new MyClass(42));
    std::cout << "Serialize using stringstream and text archive" << std::endl;
    std::stringstream oss;
    {
      ba::text_oarchive toa (oss);
      toa << srcPtr;
    }

    std::cout << "Serialized string is " << oss.tellp () << " bytes" << std::endl;

    std::stringstream iss(oss.str());
    {
      ba::text_iarchive tia (iss);
      std::shared_ptr<MyClass> dstPtr;
      tia >> dstPtr;
      assert (*srcPtr == *dstPtr);
    }

    std::cout << "Done" << std::endl;

    //Static buffer and binary
    std::cout << "Serialize using static buffer and binary archive" << std::endl;
    char testBuffer[4096];
    {
      io::stream<io::array_sink> static_os (testBuffer);
      ba::binary_oarchive static_oa (static_os);
      static_oa << srcPtr;
      std::cout << "Static buffer, buffer size: " << static_os.tellp() << std::endl;
    }

    {
      io::stream<io::array_source> static_is (testBuffer);
      ba::binary_iarchive static_ia (static_is);
      std::shared_ptr<MyClass> dstPtr;
      static_ia >> dstPtr;

      assert (*srcPtr == *dstPtr);
    }
    std::cout << "Done" << std::endl;

    //Dynamic vector
    std::cout << "Serialize using dynamic buffer and binary archive" << std::endl;
    std::vector<char> buffer;
    {
      io::stream obs (io::back_inserter (buffer));
      ba::binary_oarchive oba (obs);
      oba << srcPtr;
    }

    std::cout << "BufferSize: " << buffer.size() << std::endl;

    {
      io::stream<io::array_source> ibs (buffer.data (), buffer.size ());
      ba::binary_iarchive iba (ibs);
      std::shared_ptr<MyClass> dstPtr;
      iba >> dstPtr;

      assert (*srcPtr == *dstPtr);
    }
    std::cout << "Done" << std::endl;
}

打印


Serialize using stringstream and text archive
Serialized string is 44 bytes
Done
Serialize using static buffer and binary archive
Static buffer, buffer size: 60
Done
Serialize using dynamic buffer and binary archive
BufferSize: 60
Done
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.