Avoid std::string

From rdiez's Personal Wiki
Jump to: navigation, search

Overview

C++'s standard string class std::string has some issues and should generally be avoided.

Issues with reference-counted, copy-on-write implementations

Some std::string implementations, like the one shipped with Microsoft Visual Studio, does not use reference counting (copy on write) and is therefore very slow when copying strings around. There are some scenarios where you cannot easily pass deep pointers around, so you will end up copying strings more often than you think. After all, you want a string class that is both convenient to use and fast to run.

GCC's implementation (as of version 4.8.0) does use reference counting. Interestingly enough, the C++11 standard added a clause to forbid std::string from being reference counted. Apparently, there is some safety issue that cannot be easily fixed with C++ and/or standard library semantics. The upshot is, you can optimise your code to run very fast today, but, at some point in time, a new GCC version will remove the reference counting in order to be C++11 conformant, and your old code may experience a sudden, unexpected, drastic performance drop.

Cannot write directly to the underlying character array

There is no way to get a pointer to the underlying array of characters as a writable (non-const) memory area. The reason is that a given std::string implementation might not store the string character data in a single, contiguous block of memory, but in some dynamic data structure like a deque or a linked list of small character arrays.

This does not make much sense, because there is a c_str() member that does provide a similar "const char *" pointer. And the reason is, of course, interoperability with older C/C++ code. But that works only for the read-only (const) scenario.

If you already have C/C++ code which writes characters to a fixed-size buffer, you'll have to use a temporary buffer and copy the resulting string to the final std::string instance, which is a waste of time. This limitation becomes obvious when trying to read data from a file with the standard read() syscall. You just cannot read directly into an std::string instance, you always have to use an intermediate buffer.

std::string is very inconvenient

The usual utility functions, like sprintf(), are not available for std::string objects

A common optimisation scenario is to reuse the same string over an over in a loop as a temporary buffer for sprintf (or snprintf). The string may need to grow and reallocate memory during the first loop iterations, but after a while, it will not grow any more. However, std::string is not compatible with sprintf (see above). The lack of a good sprintf replacement prevents this kind of simple but effective optimisation.

std::ostringstream does not help either

std::ostringstream does allow some flexibility when writing to an std::string object, but it is very slow, as it tends to allocate and free memory often. Besides, not everybody likes the C++ stream library.

Alternatives

If you are developing for Windows with Visual Studio, Microsoft's CString class is a superior alternative. Methods like Format() and GetBuffer() provide a good measure of comfort and still leave room for optimisation.

Under Linux/BSD/etc, it's probably best to look around for a similar string class. String classes that were developed from the ground up with reference counting, copy-on-write semantics in mind will probably not have the same issues the C++11 standard is trying to correct in std::string.