C++ equivalent of StringBuffer/StringBuilder?

246,428

Solution 1

The C++ way would be to use std::stringstream or just plain string concatenations. C++ strings are mutable so the performance considerations of concatenation are less of a concern.

with regards to formatting, you can do all the same formatting on a stream, but in a different way, similar to cout. or you can use a strongly typed functor which encapsulates this and provides a String.Format like interface e.g. boost::format

Solution 2

The std::string.append function isn't a good option because it doesn't accept many forms of data. A more useful alternative is to use std::stringstream; like so:

#include <sstream>
// ...

std::stringstream ss;

//put arbitrary formatted data into the stream
ss << 4.5 << ", " << 4 << " whatever";

//convert the stream buffer into a string
std::string str = ss.str();

Solution 3

NOTE this answer has received some attention recently. I am not advocating this as a solution (it is a solution I have seen in the past, before the STL). It is an interesting approach and should only be applied over std::string or std::stringstream if after profiling your code you discover this makes an improvement.

I normally use either std::string or std::stringstream. I have never had any problems with these. I would normally reserve some room first if I know the rough size of the string in advance.

I have seen other people make their own optimized string builder in the distant past.

class StringBuilder {
private:
    std::string main;
    std::string scratch;

    const std::string::size_type ScratchSize = 1024;  // or some other arbitrary number

public:
    StringBuilder & append(const std::string & str) {
        scratch.append(str);
        if (scratch.size() > ScratchSize) {
            main.append(scratch);
            scratch.resize(0);
        }
        return *this;
    }

    const std::string & str() {
        if (scratch.size() > 0) {
            main.append(scratch);
            scratch.resize(0);
        }
        return main;
    }
};

It uses two strings one for the majority of the string and the other as a scratch area for concatenating short strings. It optimise's appends by batching the short append operations in one small string then appending this to the main string, thus reducing the number of reallocations required on the main string as it gets larger.

I have not required this trick with std::string or std::stringstream. I think it was used with a third party string library before std::string, it was that long ago. If you adopt a strategy like this profile your application first.

Solution 4

std::string is the C++ equivalent: It's mutable.

Solution 5

You can use .append() for simply concatenating strings.

std::string s = "string1";
s.append("string2");

I think you might even be able to do:

std::string s = "string1";
s += "string2";

As for the formatting operations of C#'s StringBuilder, I believe snprintf (or sprintf if you want to risk writing buggy code ;-) ) into a character array and convert back to a string is about the only option.

Share:
246,428

Related videos on Youtube

An̲̳̳drew
Author by

An̲̳̳drew

It gets complicated.

Updated on February 24, 2020

Comments

  • An̲̳̳drew
    An̲̳̳drew about 4 years

    Is there a C++ Standard Template Library class that provides efficient string concatenation functionality, similar to C#'s StringBuilder or Java's StringBuffer?

    • CoffeDeveloper
      CoffeDeveloper about 9 years
      the short answer is : Yes, STL has a class for that and it is std::ostringstream.
    • null
      null about 4 years
      Hey @andrew. Can you please change the accepted answer? There is a clear winning answer and it isn't the current accepted answer.
    • An̲̳̳drew
      An̲̳̳drew over 3 years
      @null it has been done!
  • Andy Shellam
    Andy Shellam about 14 years
    Not in the same way as printf or .NET's String.Format though, are they?
  • jk.
    jk. about 14 years
    its a little disingenuous to say they are the only way though
  • Andy Shellam
    Andy Shellam about 14 years
    @jk - they're the only way when comparing the formatting ability of .NET's StringBuilder, which is what the original question specifically asked. I did say "I believe" so I could be wrong, but can you show me a way to get StringBuilder's functionality in C++ without using printf?
  • jk.
    jk. about 14 years
    updated my answer to include some alternative formatting options
  • Kobor42
    Kobor42 about 11 years
    Reinventing the wheel. std::stringstream is the proper answer. See good answers below.
  • iain
    iain about 11 years
    @Kobor42 I agree with you as I point out on the first and last line of my answer.
  • bobobobo
    bobobobo about 11 years
    C++ strings are mutable: exactly. The entire reason StringBuilder exists is to cover the inefficiency of Java's immutable basic String type. In other words StringBuilder is patchwork, so we should be glad we don't need such a class in C++.
  • jk.
    jk. about 11 years
    @bobobobo immutable strings have other benefits though, its horses for courses
  • Serge Rogatch
    Serge Rogatch almost 9 years
    Don't plain string concatenations create a new object, so the same problem as with immutability in Java? Consider all variables are strings in the following example: a = b + c + d + e + f; Isn't it going to call operator+ on b and c, then operator+ on the result and d, etc.?
  • Serge Rogatch
    Serge Rogatch over 8 years
    @Hoten, as I understand, move semantics will only save copying of the object when returning from operator+. However, new string object is still needed to be created inside operator+ for storing the result of string concatenation.
  • Jan Smrčina
    Jan Smrčina about 8 years
    @jk I believe marking the std::string as const makes it immutable, so I'd call this a flexibility.
  • neuralmer
    neuralmer almost 8 years
    @SergeRogatch I have seen the Java compiler avoid multiple object creation in a stack of concatenations like that by creating a StringBuilder, using append(), and then getting the result at the end with a toString().
  • Trygve Skogsholm
    Trygve Skogsholm almost 8 years
    Hold on a minute people, the standard string class knows how to mutate itself but that does not mean the inefficiency is not there. As far as I know std::string cannot simply extend the size of its internal char*. That means mutating it in a way which requires more characters requires a reallocation and copying. It's no different than a vector of chars and it is certainly better to reserve the space you need in that case.
  • BeeOnRope
    BeeOnRope over 6 years
    I don't think the scratch string really accomplishes anything here. The number of reallocations of the main string is largely going to be a function of it's final size, not the number of append operations, unless the string implementation is really poor (i.e., doesn't use exponential growth). So "batching" up the append doesn't help because once the underlying string is large it will only grow occasionally either way. On top of that it adds a bunch of redundant copy operations, and may more reallocations (hence calls to new/delete) since you are appending to a short string.
  • BeeOnRope
    BeeOnRope over 6 years
    @TrygveSkogsholm - it is no different than a vector of chars, but of course the "capacity" of the string can be larger than its size, so not all appends need a reallocation. In general strings will use an exponential growth strategy so appending still amortizes to a linear cost operation. That's different than Java's immutable Strings in which every append operation needs to copy all characters in both Strings to a new one, so a series of appends ends up as O(n) in general.
  • iain
    iain over 6 years
    @BeeOnRope I agree with you.
  • hanshenrik
    hanshenrik about 5 years
    i'm pretty sure str.reserve(1024); would be faster than this thing
  • einpoklum
    einpoklum almost 4 years
    This is neat. I don't see why std::stringstream doesn't behave this way.
  • underscore_d
    underscore_d almost 2 years
    "std::string's += doesn't work with const char*" Yes, it does, and it has since at least C++98... m.cplusplus.com/reference/string/string/operator+=