String Builder: Building Strings with Streams on the Stack

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);
}


About the Author

John Wellbelove

John has been in the electronics business for 30 years, gradually moving over the years from pure hardware design to mostly software with hardware interface elements in a real-time environment. Over the years he has programmed in Assembler (6502, 6809, 68000), BASIC, Pascal, C & C++. He has dabbled a little in PHP/MySQL as he runs run a climbing club website and forum. http://www.southamptonrats.org. Projects have included DCT based image compression (pre-jpeg), remote imaging security systems, CCTV cameras, images analysis, real-time conveyor control. He is currently working on a template library based on the STL for images and image algorithms.

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Java developers know that testing code changes can be a huge pain, and waiting for an application to redeploy after a code fix can take an eternity. Wouldn't it be great if you could see your code changes immediately, fine-tune, debug, explore and deploy code without waiting for ages? In this white paper, find out how that's possible with a Java plugin that drastically changes the way you develop, test and run Java applications. Discover the advantages of this plugin, and the changes you can expect to see …

  • Mobile is introducing sweeping changes throughout your workplace. As a senior stakeholder driving mobile initiatives in your organization, you may be lost in a sea of technologies and claims from vendors promising rapid delivery of applications to your employees, customers, and partners. To help explain some of the topics you will need to be aware of, and to separate the must-haves from the nice-to-haves, this reference guide can help you with applying a mobile strategy in the context of application …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds