Подтвердить что ты не робот

Прямая генерация сериализации в массив char

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

Ответ 1

IIUC, вы хотите записать в предварительно выделенный массив фиксированного размера.

Вы можете использовать boost:: iostreams:: array_sink (завернутый stream, чтобы предоставить ему интерфейс std:: ostream).

Ответ 2

Если вы не знаете размер данных, которые вы отправляете заранее, это общий способ сериализации в 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(), прежде чем сериализовать его. Это очищает данные, но не освобождает память, поэтому никакого распределения не произойдет, когда ваш следующий размер данных сериализации не потребует этого.

Ответ 3

Более простая версия, чем принятый ответ с использованием 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;
}


Полный рабочий пример, скомпилированный с boost 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;
    }
}