C++ equivalent of StringBuffer/StringBuilder?
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.
Related videos on Youtube
Comments
-
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 about 9 yearsthe short answer is : Yes, STL has a class for that and it is
std::ostringstream
. -
null about 4 yearsHey @andrew. Can you please change the accepted answer? There is a clear winning answer and it isn't the current accepted answer.
-
An̲̳̳drew over 3 years@null it has been done!
-
-
Andy Shellam about 14 yearsNot in the same way as printf or .NET's String.Format though, are they?
-
jk. about 14 yearsits a little disingenuous to say they are the only way though
-
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. about 14 yearsupdated my answer to include some alternative formatting options
-
Kobor42 about 11 yearsReinventing the wheel. std::stringstream is the proper answer. See good answers below.
-
iain about 11 years@Kobor42 I agree with you as I point out on the first and last line of my answer.
-
bobobobo about 11 yearsC++ strings are mutable: exactly. The entire reason
StringBuilder
exists is to cover the inefficiency of Java's immutable basic String type. In other wordsStringBuilder
is patchwork, so we should be glad we don't need such a class in C++. -
jk. about 11 years@bobobobo immutable strings have other benefits though, its horses for courses
-
Serge Rogatch almost 9 yearsDon'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 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 insideoperator+
for storing the result of string concatenation. -
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 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 almost 8 yearsHold 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 over 6 yearsI 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 thestring
implementation is really poor (i.e., doesn't use exponential growth). So "batching" up theappend
doesn't help because once the underlyingstring
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 tonew
/delete
) since you are appending to a short string. -
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 over 6 years@BeeOnRope I agree with you.
-
hanshenrik about 5 yearsi'm pretty sure
str.reserve(1024);
would be faster than this thing -
einpoklum almost 4 yearsThis is neat. I don't see why
std::stringstream
doesn't behave this way. -
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+=