我正在尝试使用 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)
就像我之前评论的那样,这是一个陷阱。某些存档类型需要在存档析构函数中完成(例如 XML 存档)。
对于许多存档类型,简单的刷新似乎就足够了。事实上,在文本存档中,换行符通常会导致底层操作系统文本流实现的隐式刷新。
但是,为了正确起见,您需要在使用流内容之前完成存档。
这是我的简化版本,演示了所有三个:
#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