Using streams without inheritance

Started by
17 comments, last by Kylotan 22 years, 3 months ago
Recently I''ve been thinking about how useful stringstreams are for formatting text. One of my projects is a MUD which is almost exclusively about sending text to the players, which then ends up sent down a socket. The problem is this: an ostringstream is 136 bytes and a stringbuf is 96 bytes, a 240 byte addition that almost doubles the size of my Character objects. Now, if this was just for players, that would be fine, as I don''t expect more than 100 players in the game at once. But the interface has to be standardised across Players and NonPlayers, so any streaming has to be done in the base Character class. This would mean incurring that 232 byte penalty on tens of thousands of characters, meaning we''re talking about several extra megabytes of additional memory needed for this ''convenience''. I have an idea (with 2 potential implementations) for how to approximate this. There would be a single templatised << operator for Character that takes any type, and passes it to an ostringstream in order to get the string representation of that type. This is appended to an internal string buffer. Basically, the ostringstream is just used to convert any type to a string, based on prior formatting rules set by stream manipulators. Implementation 1: Just use a single static ostringstream for all instances of Character. This would work reasonably fine now, but I intend adding some multithreading later. I would then need to add some sort of mutex/critical section to it, and I can imagine that might get slow? (I hear conflicting things on such issues, and I don''t know enough about synchronisation primitives to know for sure.) Implementation 2: Create the ostringstream on the stack each time it''s needed. I can imagine that the constructor and destructor for an ostringstream are not trivial and therefore this would be inefficient too. Bear in mind that sending text to a character is done very very often. So I can''t afford for it to be a slow operation. (It doesn''t need to be hyper-efficient, but I can''t disregard efficiency entirely). So does anyone have any other ideas for an interface that provides all the versatility of iostreams, without the large memory footprint? [ MSVC Fixes | STL | SDL | Game AI | Sockets | C++ Faq Lite | Boost ]
Advertisement
Implementation 3: @$@#$#$ xxstream and implement your own thread-compatible unbloated objects?

Don''t you generally pass xxstream _references around, meaning there''s very few actual xxstream objects?

I''d construct one stream object for input and one for output, and have the socket class suck/stuff those streams.

Am I missing something?

Oh good lord, no you can''t have two streams for every PC and NPC.
One for the console output, and one for the console input.
Maybe a small pool of them on the server side if you really wanted to use them for socket streaming.

Try std::string or std::vector<char>
- The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
The idea is that each character has its own buffer area that receives formatted output. I could write to thousands of characters before any of them have that buffer flushed to a socket (or simply emptied, in the case of an NPC). This buffer area would be analogous to the .str() member function of a stringstream. It''s useful to be able to use standard functionality like the width manipulators and so on, and implementing these all over again seems like a waste of time. Currently I just have a few overridden << operators that handle the basic types, but I have to manage the buffer myself, as well as having no support for setting the width of a field since I don''t have all the same functionality that a normal ostream would have.

[ MSVC Fixes | STL | SDL | Game AI | Sockets | C++ Faq Lite | Boost ]
Could you overridd the stream operators in the PC/NPC classes write to one stream singleton used to transmit data on the socket?

That way you could get a pointer to the (N)PC you were talking to
pTalkingTo << whatTheyTyped;
and it''d be serialized into the single outgoing stream buffer with whatever additional information is need to identify the target
- The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
Sorry if I misunderstood.

If your character needs to store an buffer, then it shouldn''t know about formatting at all.

A character should store the buffer using std::string (or whatever) and takes a input string to add to it''s internal buffer. Formatting the string is done at the application level rather on a ostringstream instance than writing directly to the Char class.

  class Char{  void Add( const char *str ) {  buffer += str; }private:  std::string buffer_;};// at application level, use a single instance of stringstream// to format the string. Just remember to clear it appropriately  
The main problem with using a singleton stream is that it doesn''t store state. I can give each Character their own buffer represented as a string, that''s no problem. But iostreams store other state, such as the formatting. Although it''s true that a Character doesn''t really need to know about most formatting, this needs to be stored somewhere between calls. As I see it, this either has to be in the character (incurring a size overhead) or in the calling function (incurring a code overhead). I really don''t want to be declaring ostringstreams everytime I want to write data to a Character. That would be literally hundreds of instances in the code.

At the moment, I am doing my formatting via a function that takes a string and returns it padded it to the left or right with spaces. This works for most applications, but is ugly.

[ MSVC Fixes | STL | SDL | Game AI | Sockets | C++ Faq Lite | Boost ]
Couldn''t you use a custom stream manipulator to store the formatting state instead?
Maybe, if you explained what you mean
  #include <iostream>#include <iomanip>using	namespace	std;ostream&	my_manip( ostream &os ){	int	length = 3;	for ( int i = 0;	i < length;	++i )		os << " ";	return	os;}int	main(){	cout   << my_manip << "Hello" << endl;	return	0;}  


I was thinking of having the manipulator taking an argument that control the formatting state( ie. take a variable length ).

But it is seems that creating manipulators with arguments is non portable. VC++ uses macros to accomplish the tasks, some platforms uses template specialization.

Since this is not ideal, perhaps each Char object holds a state object which holds formatting state and the state class overloads the << operator.
I may not fully understand your description of the problem, but when do you need the formatting of the stringstream?

It seems to me that you can have the Character class store the data in any format it wants and then have it be streamable - eg some virtual write/read methods

reading and generating new objects on the receiving end can be troublesome, but is not that hard of a problem to overcome.

So why not apply the formatting during transmission - e.g. create a custom stream class that sends the data to the socket.

Then create a special form of streambuf that worries about ''packaging'' the data to effecient sizes for transmission.

This topic is closed to new replies.

Advertisement