Прямое ускорение сериализации в массив символов

Подтвердите документацию по сериализации, утверждая, что для сериализации / десериализации элементов используется двоичный / текстовый архив с потоком в базовой структуре. Это прекрасно работает, если я не хочу использовать сериализованные данные в качестве 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;
    }
}
Другие вопросы по тегам