I had a requirement for building strings for logging, but the std::ostringstream was
less than optimum. Firstly, it required more than one line of code to build the string and
secondly, it uses the heap for buffering. The code here describes a simple, stack based, string builder class that
that uses a fixed array as the workspace for a string stream.
How the String Builder Works
The string builder works by creating a class derived from streambuf (Stream_Buffer) that has its
buffer set to a fixed internal array, and using that as the buffer for the ostream derived object (Stream).
The Stream_Buffer discards any characters that would cause the buffer to overflow. An overloaded << operator
in the String_Builder class adds objects to the internal stream. A conversion operator to
std::string is provided as well as two functions ‘str’ and ‘c_str’ to convert to std::string
and const char*.
The default size for the buffer is set to 256 characters. Larger buffers can be
accommodated by using a larger template parameter.
Example of the String Builder
void Log(const std::string &text) { // Log the text somewhere... } int value = 10; Log(String_Builder<>() << "The value is " << value << "n"); Log(String_Builder<1000>() << "A really long string up to 1000 characters");
The String Builder Code
Following is the code for thie String_Builder class:
#include <ostream> #include <streambuf> template <const int MAX_CHARACTERS = 256> class String_Builder { private: //***************************************************************** // Special stream buffer //***************************************************************** class Stream_Buffer : public std::streambuf { public: //************************************************************** // Constructor //************************************************************** Stream_Buffer() { // Set the pointer to the internal buffer. setp(buffer, buffer + MAX_CHARACTERS); } //************************************************************** // Returns a null terminated string. //************************************************************** const char *c_str() const { *pptr() = 0; return (pbase()); } protected: //************************************************************** // Overridden Overflow() //************************************************************** int_type overflow(int_type c = 0) { // Don't do anything if we have no more room. return (0); } private: // The buffer that accumulates the characters. // Leave room for a terminating zero. char buffer[MAX_CHARACTERS + 1]; }; //***************************************************************** // Special stream //***************************************************************** class Stream : public std::ostream { public: //************************************************************** // Constructor //************************************************************** Stream() : std::ostream(&stream_buffer) { } //************************************************************** // Returns a null terminated string. //************************************************************** const char *c_str() const { return (stream_buffer.c_str()); } private: Stream_Buffer stream_buffer; // The stream that builds the string. }; public: //********************************************************************* // Output stream operator. //********************************************************************* template<typename T> String_Builder &operator <<(const T &value) { builder << value; return (*this); } //********************************************************************* // Conversion operator to std::string //********************************************************************* operator std::string() const { return (std::string(builder.c_str())); } //********************************************************************* // Conversion to std::string //********************************************************************* std::string str() const { return (std::string(builder.c_str())); } //********************************************************************* // Pointer to the internal C string. //********************************************************************* const char *c_str() const { return (builder.c_str()); } private: Stream builder; // The stream used to accumulate text. }; //********************************************************************* // Operator to stream to a std::ostream. //********************************************************************* template <const int MAX_CHARACTERS> inline std::ostream &operator <<(std::ostream &os, const String_Builder<MAX_CHARACTERS> &sb) { os << std::string(sb); return (os); }