Link to home
Start Free TrialLog in
Avatar of Spencer Simpson
Spencer SimpsonFlag for United States of America

asked on

dump one stream into another without multiple copies

I'm working on a little utility application which needs to have a place to send error messages even if a console or file isn't available yet.

The idea is to cache messages into a stringstream until a file can be opened (fstream), then dump the contents of the cache stream into the "true" message stream.  Even if it has to wait until the destructor is called.

Stripped down to its essentials:

class ostream_sink 
{
 private:
 bool m_caching;
 std::string m_filename;
 std::ostringstream *m_cache;
 std::ofstream *m_dest;
 // imagine constructor and destructor details, and setting the file name
 bool open_file(); // implementation omitted
 public:
 void start_caching() { m_caching = true; }
 void stop_caching(); // question is about implmenting this routine

 std::ostream &stream();
 std::ostream &stream() const;
 template <class T> ostream_sink &operator<<(T const &v) { stream() << v; }
 template <class T> ostream_sink &operator<<(T const &v) const { stream() << v; }
};

 std::ostream &stream() const 
{
 if (m_caching) 
    return *m_cache;
   else return *m_dest; 
}

std::ostream &ostream_sink::stream ()
{ if (m_caching) if (open_file()) stop_caching(); 
   if (m_caching) 
      return *m_cache; 
      else return *m_dest; 
}

Open in new window


I suppose I could always use the stringstream's str() mehod:

ostream_sink::stop_caching ()
{
 if (m_caching) 
  {
   (*m_dest) << m_cache->str();
   m_cache->str(string()); 
   m_caching = false;
 }
}

Open in new window


but that string gets copied twice.   Is there a way do dump the cache's streambuf into the file stream's?  You certainly can't swap a stringbuf with a filebuf.....
Avatar of jkr
jkr
Flag of Germany image

The snippets above actually do look OK. Could you provide some more code? Maybe the problem is located elsewhere...
Avatar of Spencer Simpson

ASKER

It's not a "somethign doesn't work" problem, it's a question of efficiency.    The snippets provide a simplified example of the concept.

m_cache->str() returns a copy of the string, which might have a large amount of text in it. Putting it into the m_dest copies the text again.  So not only is a large amount of memory allocated and deallocated for the temporary string, there are potentially two fairly large copy operations involved.
Ah, OK, now I see what you mean. In that case, you could use a 'basic_filebuf' directly and use the stringstream's buffer as the source using 'pubsetbuf()', see e.g. the example at http://msdn.microsoft.com/en-us/library/vstudio/tzf8k3z8%28v=vs.100%29.aspx ("basic_filebuf Class" - scroll down). However, I haven't tried that myself.
Oh, maybe also of interst in this context: http://stackoverflow.com/questions/2079912/simpler-way-to-create-a-c-memorystream-from-char-size-t-without-copying-t ("Simpler way to create a C++ memorystream from (char*, size_t), without copying the data?")
After some examination, it appears that basic_streambuf has protected member functions that would let you do precisely this if they weren't protected.

The solution appears to be abandoning this approach and taking the one the STL gods would tell you to take, if you asked you about anything past the basic funcitonality of these streams: roll your own streambuf class.
ASKER CERTIFIED SOLUTION
Avatar of ambience
ambience
Flag of Pakistan image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial