Is it possible to reuse a binary_oarchive instance?

My question is the same as discussed in this thread from five years ago (which does not have a good answer).

I serialize my objects to a byte buffer, for example:

std::string serial_str;
for (i = 1; i < 10000; i++)
{
    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;

    s.flush();

    // code to send serial_str content to another process, omitted.

    serial_str.clear(); // clear the buffer so it can be reused to serialize the next object
}    

When I do this in a loop, the performance is pretty bad: I get ~ 14,000 objects / sec.

I identified the problem before recreating the binary_archive. If I just write on the same line with the same archive instance in a loop, I get ~ 220,000 objects / sec, but then the objects are serialized sequentially sequentially, and this is not what I want: I want to clean and reuse one and the same buffer (look for its beginning) after each serialization of the object.

How can i do this?

+3
source
3

, , . Oarchive , , , ( ), "reset" , - .

, :

Oarchive (, ), :

boost::archive::binary_oarchive oa(s, boost::archive::no_codecvt | boost::archive::no_header);

, oarchive, . , , ints, floats .., , , .., , . Boost , - , :

oa.template register_type<std::string>();
oa.template register_type<MyClass>();
oa.template register_type<std::shared_ptr<MyClass> >();

.. , std::vectors , std:: shared_ptrs .. . , iarchive , .

, iarchive , oarchive ( , mpl, ).

iarchive iarchive, :

  • ( / reset)

, , oarchive/iarchive , . , .

+2

, . . , , :

boost::iostreams::basic_array<char> sink; // target buffer 
boost::iostreams::stream<boost::iostreams::basic_array<char> > os;  // stream wrapper around it
boost::archive::binary_oarchive oa;  // archive which uses this stream

, , :

os.close();
os.open(sink);

, . , .

: Writer . Reader ( )

#include <iostream>
#include <fstream>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/serialization/export.hpp>
#include <boost/serialization/access.hpp>

class A;
class Writer {
    char *buf;
    int len;
    boost::iostreams::basic_array<char> sink;
    boost::iostreams::stream<boost::iostreams::basic_array<char> > os;
    boost::archive::binary_oarchive oa;
public:
    Writer(char *_buf, int _len): buf(_buf), len(_len), sink(buf, len), os(sink), oa(os) {}
    void write(A* a) {
        oa << a;
    }
    void reset() {
        os.close();
        os.open(sink);
    }
};
class Reader {
    char *buf;
    int len;
    boost::iostreams::basic_array_source<char> src;
    boost::iostreams::stream<boost::iostreams::basic_array_source<char> > is;
    boost::archive::binary_iarchive ia;
public:
    Reader(char *_buf, int _len): buf(_buf), len(_len), src(buf, len), is(src), ia(is) {}
    A* read() {
        A* a;
        ia >> a;
        return a;
    }
    void reset() {
        is.close();
        is.open(src);
    }
};

int main(int argc, char **argv) {
    // to memory
    char buffer[4096] = {0};

    Writer w(buffer, sizeof(buffer));
    A *a1 = new A(5);
    w.write(a1);

    Reader r(buffer, sizeof(buffer));
    A *a2 (NULL);
    a2 = r.read();

    assert(*a1 == *a2);
    std::cout << "Simple ok\n";

    // test reuse
    w.reset();
    r.reset();

    A *a3 (NULL);
    w.write(new A(10));
    a3 = r.read();

    assert(*a3 == A(10));
    std::cout << "Reuse ok\n";
};

class A
{
private:
  friend class boost::serialization::access;
  int i;

  template <typename Archive>
  void serialize(Archive& ar, const unsigned int version) {
    std::cout << "serialize A\n";
    ar & i;
  }
public:
  A(): i(0) {};
  A(int _i): i(_i) {};
  virtual bool operator==(const A&r) { return i == r.i; };

  virtual ~A() {};
  virtual void whoa() {std::cout << "I am A!\n";};
  virtual const char* me() { return "A"; };
};
+2

One solution, without requiring more attention, is to save the last line length and get the substring using the last length and the actual length (will be the last line added to the output). You can restart every 10 or 100 iterations binary_oarchiveso as not to accumulate many past encoded objects in serial_str.

0
source

All Articles