CString (MFC)
Prev | Chapter 13. String Classes | Next

## CString (MFC)

A common lament seen in various newsgroups deals with the Standard string class as opposed to the Microsoft Foundation Class called CString. Often programmers realize that a standard portable answer is better than a proprietary nonportable one, but in porting their application from a Win32 platform, they discover that they are relying on special functions offered by the CString class.

Things are not as bad as they seem. In this message, Joe Buck points out a few very important things:

- The Standard `string` supports all the operations that CString does, with three exceptions.

- Two of those exceptions (whitespace trimming and case conversion) are trivial to implement. In fact, we do so on this page.

- The third is `CString::Format`, which allows formatting in the style of `sprintf`. This deserves some mention:

The old libg++ library had a function called form(), which did much the same thing. But for a Standard solution, you should use the stringstream classes. These are the bridge between the iostream hierarchy and the string class, and they operate with regular streams seamlessly because they inherit from the iostream hierarchy. An quick example:

       #include <iostream>
       #include <string>
       #include <sstream>

       string f (string& incoming)     // incoming is "foo  N"
       {
           istringstream   incoming_stream(incoming);
           string          the_word;
           int             the_number;

           incoming_stream >> the_word        // extract "foo"
                           >> the_number;     // extract N

           ostringstream   output_stream;
           output_stream << "The word was " << the_word
                         << " and 3*N was " << (3*the_number);

           return output_stream.str();
       }

A serious problem with CString is a design bug in its memory allocation. Specifically, quoting from that same message:

       CString suffers from a common programming error that results in
       poor performance.  Consider the following code:

       CString n_copies_of (const CString& foo, unsigned n)
       {
               CString tmp;
               for (unsigned i = 0; i < n; i++)
                       tmp += foo;
               return tmp;
       }

       This function is O(n^2), not O(n).  The reason is that each +=
       causes a reallocation and copy of the existing string.  Microsoft
       applications are full of this kind of thing (quadratic performance
       on tasks that can be done in linear time) -- on the other hand,
       we should be thankful, as it's created such a big market for high-end
       ix86 hardware. :-)

       If you replace CString with string in the above function, the
       performance is O(n).

Joe Buck also pointed out some other things to keep in mind when comparing CString and the Standard string class:

- CString permits access to its internal representation; coders who exploited that may have problems moving to `string`.

- Microsoft ships the source to CString (in the files MFC\SRC\Str{core,ex}.cpp), so you could fix the allocation bug and rebuild your MFC libraries. Note: It looks like the CString shipped with VC++6.0 has fixed this, although it may in fact have been one of the VC++ SPs that did it.

- `string` operations like this have O(n) complexity if the implementors do it correctly. The libstdc++ implementors did it correctly. Other vendors might not.

- While parts of the SGI STL are used in libstdc++, their string class is not. The SGI `string` is essentially `vector<char>` and does not do any reference counting like libstdc++'s does. (It is O(n), though.) So if you're thinking about SGI's string or rope classes, you're now looking at four possibilities: CString, the libstdc++ string, the SGI string, and the SGI rope, and this is all before any allocator or traits customizations! (More choices than you can shake a stick at -- want fries with that?)

Prev | Up | Next
Shrink to Fit | Home | Part VI. Localization