11

I have a std::vector<int> and I want serialize it. For this purpose I am trying to use a std::stringstream

 vector<int> v;
 v.resize(10);
 for (int i=0;i<10;i++)
 v[i]=i;


 stringstream ss (stringstream::in | stringstream::out |stringstream::binary);

However when I copy the vector to the stringstream this copy it as character

ostream_iterator<int> it(ss);
copy(v.begin(),v.end(),it);

the value that inserted to buffer(_Strbuf) is "123456789"

I sucssesed to write a workaround solution

for (int i=1;i<10;i++)
   ss.write((char*)&p[i],sizeof(int));

I want to do it something like first way by using std function like copy

thanks Herzl

the_drow
  • 18,571
  • 25
  • 126
  • 193
herzl shemuelian
  • 3,346
  • 8
  • 34
  • 49

4 Answers4

10

Actually, this is your workaround but it may be used with std::copy() algorithm.

   template<class T>
   struct serialize
   {
      serialize(const T & i_value) : value(i_value) {}
      T value;
   };

   template<class T>
   ostream& operator <<(ostream &os, const serialize<T> & obj)
   {
      os.write((char*)&obj.value,sizeof(T));
      return os;
   }

Usage

ostream_iterator<serialize<int> > it(ss);
copy(v.begin(),v.end(),it);
Stas
  • 11,571
  • 9
  • 40
  • 58
  • I like this approach in general, but it is often an error to blindly output memory like this. You still need to write something that can properly serialize each type. – Fred Nurk Feb 01 '11 at 15:14
  • Completely agree. I would never use such code in production. I would prefer above-mentioned "for" cycle :-) – Stas Feb 01 '11 at 15:16
2

I know this is not an answer to your problem, but if you are not limited to the STL you could try (boost serialization) or google protocol buffers

Boost even has build-in support for de-/serializing STL containers (http://www.boost.org/doc/libs/1_45_0/libs/serialization/doc/tutorial.html#stl)

Martin
  • 968
  • 3
  • 10
  • 19
1

To use std::copy with ostream::write, you'd need to write your own output iterator that knows how to correctly serialize the type. That said, I'm not sure what you expect to gain from this approach, but here's a first pass at that for an example:

struct ostream_write_int
  : std::iterator<std::output_iterator_tag, int, void, void, void>
{
  std::ostream *s;
  ostream_write_int(std::ostream &s) : s (&s) {}

  ostream_write_int& operator++() { return *this; }
  ostream_write_int& operator++(int) { return *this; }
  ostream_write_int& operator*() { return *this; }

  void operator=(int x) {
    s->write(reinterpret_cast<char*>(&x), sizeof(x));
  }
};

This could be templated only if you defer the serialization logic to some other function (as the formatted stream iterators do to operator<<).

Fred Nurk
  • 13,952
  • 4
  • 37
  • 63
1

Like Fred, I don't see the point of this, what you are effectively trying to do is:

ss.rdbuf()->sputn(reinterpret_cast<char*>(&v[0]), sizeof(int) * v.size());
Nim
  • 33,299
  • 2
  • 62
  • 101
  • 1
    This is not very readable. I would never understand such code easily. – the_drow Feb 01 '11 at 15:17
  • @the_drow, "never" is a long time! ;), you can replace `.rdbuf()->sputn(` with `.write(` if you want, it's the same thing.. – Nim Feb 01 '11 at 15:23
  • 1
    This is true for the case of a vector, but an iterator which writes each item (as in mine or Stas's answers) can be used with any input iterators, such as from a std::list. – Fred Nurk Feb 01 '11 at 15:24
  • @Nim: I didn't say that I would never understand that code. I said that this kind of code cannot be read easily. It took me two seconds to figure it out. – the_drow Feb 01 '11 at 16:06
  • @the_drow: Welcome to C++. :) @Nim: I didn't point out what I really meant. What you point out is only a special case for a very specific circumstance which, I suspect, is only used as an example in the question rather than being the entire scope. For example, in addition to a different container, the serialization will be different for other types, or even just for an int when using htonl. – Fred Nurk Feb 01 '11 at 16:43
  • @FredNurk: I am not new to C++. You just don't do those stuff unless you have a really good reason to do so and then you should leave a comment. – the_drow Feb 01 '11 at 16:58
  • @Fred, again, I agree, all I offered is the effective case (i.e. whether you copy the array one by one or all as one), both your code and mine does the same thing (given it's a vector of ints). Yours is more flexible (can support different containers, types, endian etc.), mine caters for a specific need. It's up to the OP to be smart enough to realise what to use when... – Nim Feb 01 '11 at 18:17
  • @Nim: Okay, maybe that's the root of my confusion here: the question is about how to use std::copy, not about how to write a vector; and your answer only is about the latter instead of the former. – Fred Nurk Feb 01 '11 at 18:20
  • This solution does not work with the cereal (serialization) library, nor any rdbuf() solution. For some reason I have to create a string and pass in the c_str() and length and then construct the stringstream with that. – Andrew Jan 29 '17 at 20:37