views:

126

answers:

4

In the wonderful world of C# i can create a memory stream without specifying its size, write into it and then just take the underlying buffer.

How can i do the same in c++? basicly i need to do:

memory_stream  ms(GROW_AS_MUCH_AS_YOU_LIKE);

ms << someLargeObjects << someSmallObjects << someObjectsWhosSizeIDontKnow;

unsigned char* buffer = ms.GetBuffer();
int bufferSize = ms.GetBufferSize();

rawNetworkSocket.Send(buffer, bufferSize);

By the way I have boost in my project though I'm not all that familiar with it.

Thank you.

+1  A: 

You may want to look at std::stringstream for that purpose. The stream will grow as required. Unless you want to leave the objects in binary instead of ASCII, in which case you could take a look at the streambuf objects and implementations.

Note that C++ does not have reflection or double/multiple dispatch, so you will have to provide support for the unknown sized object yourself:

class unknown_base {
   virtual void dump( std::ostream & ) const;
};
std::ostream& operator<<( std::ostream& o, unknown_base const & obj ) {
   obj.dump( o );
   return o;
}
std::string serialize( std::vector<unknown_base*> const & data ) {
   std::ostringstream st;
   for ( std::vector<unknown_base*>::const_iterator it = data.begin(), end = data.end();
         it != end; ++it ) {
      st << **it; // double dereference: iterator, pointer
   }
   return st.str();
}
David Rodríguez - dribeas
Why would `std::stringstream` not work for binary objects ? It can work on anything. Simply write or << any thing you want, and get the resulting `std::string` object, that can contain anything, including `0` (the C character string termination character) that does not have the same meaning in the middle of an `std::string`,
Didier Trosset
@Didier the convention is that operator << to a ostream writes something human readable.
Pete Kirkham
@Pete: You can also use the write() member function of `std::stringstream`.
Didier Trosset
If you use a `ostream` to print basic types or types from the library that support the `operator<<` then it will be written in human-readable form. I should not have said ASCII, but rather human-readable.
David Rodríguez - dribeas
A: 

Since you are talking about network, it seems awfully like you want to create some kind of message and send it over the wire.

There are libraries to create messages and generate APIs for these messages, the most famous being Google Protocol Buffers (protobuf for short). It lets you describe the syntax of your message in a short file (custom format) and then automatically generate the API to decode this message in C++ / Python / Java

Advantages include:

  • interoperability, which also mean the possibility of inspecting a message with a scripting language here, handy when debugging.
  • version handling (backward and forward compatibility), because we know you'll soon modify the message but perhaps not upgrade everything at once
  • text / binary output. Text is handy for debugging, Binary is required when every bit count

Also, it's possible to use the text output and compress it with LZO or such to gain some space :)

Matthieu M.
that would be great, but i already have a custom protocol and API for passing messages, and my messages are going to be in xml, and my client side is C#...what i thought to do was to use boost::serialization to transfer my messages to xml, take the generated stream take the buffer and send as is to the C# side
Hellfrost
Don't use serialization for that. It ties the 2 separate entities together. You could perfectly write a C# API generator for Google (given their war with microsoft they are unlikely to do it themselves). Or use another messenging scheme. But serialization is meant for the same binary to decode the object, if you had a single field to one object then you have to immediately update the C# side or it just stops working... and you have to have the same model on C# side too: it's a maintenance hell. You need to define a formal interface (xml if you have to :/ or json etc...).
Matthieu M.
A: 

On Boost side there is Iostreams which is very similiar.

weismat
+4  A: 
#include <sstream>

std::ostringstream  buffer; // no growth specification necessary
buffer << "a char buffer" << customObject << someOtherObject;

std::string contents = buffer.str();
size_t bufferSize = contents.size();

rawNetworkSocket.Send(contents); // you can take the size in Send

Using this approach you will have to parse the result where you receive it (as the code above just transforms your data into an unstructured string.

Another problem with it is that since C++ doesn't support reflection, you will have to define operator << for your objects. This is the code for a Custom class:

template<typename C, typename T>
std::basic_ostream<C,T>& operator << (
    std::basic_ostream<C,T>& out, const Custom& object)
{
    out << object.member1 << "," << object.member2 /* ... */ << object.memberN;
    return out;
}

If you want structured serialization, have a look at boost::serialization.

utnapistim