Прямое ускорение сериализации в массив символов
Подтвердите документацию по сериализации, утверждая, что для сериализации / десериализации элементов используется двоичный / текстовый архив с потоком в базовой структуре. Это прекрасно работает, если я не хочу использовать сериализованные данные в качестве std::string, но я намерен преобразовать их непосредственно в буфер char*. Как я могу добиться этого без создания временной строки?
Решено! Для тех, кто хотел пример:
char buffer[4096];
boost::iostreams::basic_array_sink<char> sr(buffer, buffer_size);
boost::iostreams::stream< boost::iostreams::basic_array_sink<char> > source(sr);
boost::archive::binary_oarchive oa(source);
oa << serializable_object;
2 ответа
IIUC, вы хотели бы записать в предварительно выделенный массив фиксированного размера.
Для этого вы можете использовать boost:: iostreams:: array_sink (обернутый потоком, чтобы дать ему интерфейс std::ostream).
Если вы не знаете размер данных, которые вы отправляете заранее, это общий способ сериализации в std::string
:
// serialize obj into an std::string
std::string serial_str;
boost::iostreams::back_insert_device<std::string> inserter(serial_str);
boost::iostreams::stream<boost::iostreams::back_insert_device<std::string> > s(inserter);
boost::archive::binary_oarchive oa(s);
oa << obj;
// don't forget to flush the stream to finish writing into the buffer
s.flush();
// now you get to const char* with serial_str.data() or serial_str.c_str()
Для десериализации используйте
// wrap buffer inside a stream and deserialize serial_str into obj
boost::iostreams::basic_array_source<char> device(serial_str.data(), serial_str.size());
boost::iostreams::stream<boost::iostreams::basic_array_source<char> > s(device);
boost::archive::binary_iarchive ia(s);
ia >> obj;
Это работает как очарование, я использую это для отправки данных с MPI.
Это можно сделать очень быстро, если вы сохраните serial_str
в память, и просто позвонить serial_str.clear()
прежде чем сериализовать в него. Это очищает данные, но не освобождает какую-либо память, поэтому никакого выделения не произойдет, если ваш следующий размер данных сериализации не требует этого.
Более простая версия, чем принятый ответ с использованием std::stringstream
:
// access data with .data() and size with .size()
using RawDataBuffer = std::string;
RawDataBuffer serialize(const Foo &obj) {
std::stringstream ss;
boost::archive::binary_oarchive oa(ss);
oa << obj;
return ss.str();
}
Foo deserialize(const RawDataBuffer &data) {
std::stringstream ss(data);
boost::archive::binary_iarchive ia(ss);
Foo obj; // Foo must be default-constructible
ia >> obj;
return obj;
}
Полный рабочий пример скомпилирован с бустом 1.66:
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/serialization/access.hpp>
#include <sstream>
#include <iostream>
class Foo {
public:
Foo() = default;
Foo(int i) : _i(i)
{}
int get() const
{ return _i; }
protected:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive &ar, const unsigned int /* version */ )
{
ar & _i;
}
private:
int _i;
};
// access data with .data() and size with .size()
using RawDataBuffer = std::string;
RawDataBuffer serialize(const Foo &obj) {
std::stringstream ss;
boost::archive::binary_oarchive oa(ss);
oa << obj;
return ss.str();
}
Foo deserialize(const RawDataBuffer &data) {
std::stringstream ss(data);
boost::archive::binary_iarchive ia(ss);
Foo obj; // Foo must be default-constructible
ia >> obj;
return obj;
}
int main()
{
RawDataBuffer buff;
{
Foo fortyTwo(42);
buff = serialize(fortyTwo);
}
{
Foo reborn;
reborn = deserialize(buff);
std::cout << "Reborn from " << reborn.get() << std::endl;
}
}