8a29fdfd23
* doc/xml/manual/configure.xml: Update descriptions of options affecting dual ABI and add cross-references. * doc/xml/manual/strings.xml: Clarify that string isn't COW now. * doc/xml/manual/using.xml: Document ABI transition. * doc/html/*: Regenerate. From-SVN: r222262
365 lines
22 KiB
HTML
365 lines
22 KiB
HTML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Chapter 7. Strings</title><meta name="generator" content="DocBook XSL-NS Stylesheets V1.78.1" /><meta name="keywords" content="ISO C++, library" /><meta name="keywords" content="ISO C++, runtime, library" /><link rel="home" href="../index.html" title="The GNU C++ Library" /><link rel="up" href="std_contents.html" title="Part II. Standard Contents" /><link rel="prev" href="traits.html" title="Traits" /><link rel="next" href="localization.html" title="Chapter 8. Localization" /></head><body><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 7.
|
||
Strings
|
||
|
||
</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="traits.html">Prev</a> </td><th width="60%" align="center">Part II.
|
||
Standard Contents
|
||
</th><td width="20%" align="right"> <a accesskey="n" href="localization.html">Next</a></td></tr></table><hr /></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a id="std.strings"></a>Chapter 7.
|
||
Strings
|
||
<a id="id-1.3.4.5.1.1.1" class="indexterm"></a>
|
||
</h2></div></div></div><div class="toc"><p><strong>Table of Contents</strong></p><dl class="toc"><dt><span class="section"><a href="strings.html#std.strings.string">String Classes</a></span></dt><dd><dl><dt><span class="section"><a href="strings.html#strings.string.simple">Simple Transformations</a></span></dt><dt><span class="section"><a href="strings.html#strings.string.case">Case Sensitivity</a></span></dt><dt><span class="section"><a href="strings.html#strings.string.character_types">Arbitrary Character Types</a></span></dt><dt><span class="section"><a href="strings.html#strings.string.token">Tokenizing</a></span></dt><dt><span class="section"><a href="strings.html#strings.string.shrink">Shrink to Fit</a></span></dt><dt><span class="section"><a href="strings.html#strings.string.Cstring">CString (MFC)</a></span></dt></dl></dd></dl></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="std.strings.string"></a>String Classes</h2></div></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a id="strings.string.simple"></a>Simple Transformations</h3></div></div></div><p>
|
||
Here are Standard, simple, and portable ways to perform common
|
||
transformations on a <code class="code">string</code> instance, such as
|
||
"convert to all upper case." The word transformations
|
||
is especially apt, because the standard template function
|
||
<code class="code">transform<></code> is used.
|
||
</p><p>
|
||
This code will go through some iterations. Here's a simple
|
||
version:
|
||
</p><pre class="programlisting">
|
||
#include <string>
|
||
#include <algorithm>
|
||
#include <cctype> // old <ctype.h>
|
||
|
||
struct ToLower
|
||
{
|
||
char operator() (char c) const { return std::tolower(c); }
|
||
};
|
||
|
||
struct ToUpper
|
||
{
|
||
char operator() (char c) const { return std::toupper(c); }
|
||
};
|
||
|
||
int main()
|
||
{
|
||
std::string s ("Some Kind Of Initial Input Goes Here");
|
||
|
||
// Change everything into upper case
|
||
std::transform (s.begin(), s.end(), s.begin(), ToUpper());
|
||
|
||
// Change everything into lower case
|
||
std::transform (s.begin(), s.end(), s.begin(), ToLower());
|
||
|
||
// Change everything back into upper case, but store the
|
||
// result in a different string
|
||
std::string capital_s;
|
||
capital_s.resize(s.size());
|
||
std::transform (s.begin(), s.end(), capital_s.begin(), ToUpper());
|
||
}
|
||
</pre><p>
|
||
<span class="emphasis"><em>Note</em></span> that these calls all
|
||
involve the global C locale through the use of the C functions
|
||
<code class="code">toupper/tolower</code>. This is absolutely guaranteed to work --
|
||
but <span class="emphasis"><em>only</em></span> if the string contains <span class="emphasis"><em>only</em></span> characters
|
||
from the basic source character set, and there are <span class="emphasis"><em>only</em></span>
|
||
96 of those. Which means that not even all English text can be
|
||
represented (certain British spellings, proper names, and so forth).
|
||
So, if all your input forevermore consists of only those 96
|
||
characters (hahahahahaha), then you're done.
|
||
</p><p><span class="emphasis"><em>Note</em></span> that the
|
||
<code class="code">ToUpper</code> and <code class="code">ToLower</code> function objects
|
||
are needed because <code class="code">toupper</code> and <code class="code">tolower</code>
|
||
are overloaded names (declared in <code class="code"><cctype></code> and
|
||
<code class="code"><locale></code>) so the template-arguments for
|
||
<code class="code">transform<></code> cannot be deduced, as explained in
|
||
<a class="link" href="http://gcc.gnu.org/ml/libstdc++/2002-11/msg00180.html" target="_top">this
|
||
message</a>.
|
||
|
||
At minimum, you can write short wrappers like
|
||
</p><pre class="programlisting">
|
||
char toLower (char c)
|
||
{
|
||
return std::tolower(c);
|
||
} </pre><p>(Thanks to James Kanze for assistance and suggestions on all of this.)
|
||
</p><p>Another common operation is trimming off excess whitespace. Much
|
||
like transformations, this task is trivial with the use of string's
|
||
<code class="code">find</code> family. These examples are broken into multiple
|
||
statements for readability:
|
||
</p><pre class="programlisting">
|
||
std::string str (" \t blah blah blah \n ");
|
||
|
||
// trim leading whitespace
|
||
string::size_type notwhite = str.find_first_not_of(" \t\n");
|
||
str.erase(0,notwhite);
|
||
|
||
// trim trailing whitespace
|
||
notwhite = str.find_last_not_of(" \t\n");
|
||
str.erase(notwhite+1); </pre><p>Obviously, the calls to <code class="code">find</code> could be inserted directly
|
||
into the calls to <code class="code">erase</code>, in case your compiler does not
|
||
optimize named temporaries out of existence.
|
||
</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a id="strings.string.case"></a>Case Sensitivity</h3></div></div></div><p>
|
||
</p><p>The well-known-and-if-it-isn't-well-known-it-ought-to-be
|
||
<a class="link" href="http://www.gotw.ca/gotw/" target="_top">Guru of the Week</a>
|
||
discussions held on Usenet covered this topic in January of 1998.
|
||
Briefly, the challenge was, <span class="quote">“<span class="quote">write a 'ci_string' class which
|
||
is identical to the standard 'string' class, but is
|
||
case-insensitive in the same way as the (common but nonstandard)
|
||
C function stricmp()</span>”</span>.
|
||
</p><pre class="programlisting">
|
||
ci_string s( "AbCdE" );
|
||
|
||
// case insensitive
|
||
assert( s == "abcde" );
|
||
assert( s == "ABCDE" );
|
||
|
||
// still case-preserving, of course
|
||
assert( strcmp( s.c_str(), "AbCdE" ) == 0 );
|
||
assert( strcmp( s.c_str(), "abcde" ) != 0 ); </pre><p>The solution is surprisingly easy. The original answer was
|
||
posted on Usenet, and a revised version appears in Herb Sutter's
|
||
book <span class="emphasis"><em>Exceptional C++</em></span> and on his website as <a class="link" href="http://www.gotw.ca/gotw/029.htm" target="_top">GotW 29</a>.
|
||
</p><p>See? Told you it was easy!</p><p>
|
||
<span class="emphasis"><em>Added June 2000:</em></span> The May 2000 issue of C++
|
||
Report contains a fascinating <a class="link" href="http://lafstern.org/matt/col2_new.pdf" target="_top"> article</a> by
|
||
Matt Austern (yes, <span class="emphasis"><em>the</em></span> Matt Austern) on why
|
||
case-insensitive comparisons are not as easy as they seem, and
|
||
why creating a class is the <span class="emphasis"><em>wrong</em></span> way to go
|
||
about it in production code. (The GotW answer mentions one of
|
||
the principle difficulties; his article mentions more.)
|
||
</p><p>Basically, this is "easy" only if you ignore some things,
|
||
things which may be too important to your program to ignore. (I chose
|
||
to ignore them when originally writing this entry, and am surprised
|
||
that nobody ever called me on it...) The GotW question and answer
|
||
remain useful instructional tools, however.
|
||
</p><p><span class="emphasis"><em>Added September 2000:</em></span> James Kanze provided a link to a
|
||
<a class="link" href="http://www.unicode.org/reports/tr21/tr21-5.html" target="_top">Unicode
|
||
Technical Report discussing case handling</a>, which provides some
|
||
very good information.
|
||
</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a id="strings.string.character_types"></a>Arbitrary Character Types</h3></div></div></div><p>
|
||
</p><p>The <code class="code">std::basic_string</code> is tantalizingly general, in that
|
||
it is parameterized on the type of the characters which it holds.
|
||
In theory, you could whip up a Unicode character class and instantiate
|
||
<code class="code">std::basic_string<my_unicode_char></code>, or assuming
|
||
that integers are wider than characters on your platform, maybe just
|
||
declare variables of type <code class="code">std::basic_string<int></code>.
|
||
</p><p>That's the theory. Remember however that basic_string has additional
|
||
type parameters, which take default arguments based on the character
|
||
type (called <code class="code">CharT</code> here):
|
||
</p><pre class="programlisting">
|
||
template <typename CharT,
|
||
typename Traits = char_traits<CharT>,
|
||
typename Alloc = allocator<CharT> >
|
||
class basic_string { .... };</pre><p>Now, <code class="code">allocator<CharT></code> will probably Do The Right
|
||
Thing by default, unless you need to implement your own allocator
|
||
for your characters.
|
||
</p><p>But <code class="code">char_traits</code> takes more work. The char_traits
|
||
template is <span class="emphasis"><em>declared</em></span> but not <span class="emphasis"><em>defined</em></span>.
|
||
That means there is only
|
||
</p><pre class="programlisting">
|
||
template <typename CharT>
|
||
struct char_traits
|
||
{
|
||
static void foo (type1 x, type2 y);
|
||
...
|
||
};</pre><p>and functions such as char_traits<CharT>::foo() are not
|
||
actually defined anywhere for the general case. The C++ standard
|
||
permits this, because writing such a definition to fit all possible
|
||
CharT's cannot be done.
|
||
</p><p>The C++ standard also requires that char_traits be specialized for
|
||
instantiations of <code class="code">char</code> and <code class="code">wchar_t</code>, and it
|
||
is these template specializations that permit entities like
|
||
<code class="code">basic_string<char,char_traits<char>></code> to work.
|
||
</p><p>If you want to use character types other than char and wchar_t,
|
||
such as <code class="code">unsigned char</code> and <code class="code">int</code>, you will
|
||
need suitable specializations for them. For a time, in earlier
|
||
versions of GCC, there was a mostly-correct implementation that
|
||
let programmers be lazy but it broke under many situations, so it
|
||
was removed. GCC 3.4 introduced a new implementation that mostly
|
||
works and can be specialized even for <code class="code">int</code> and other
|
||
built-in types.
|
||
</p><p>If you want to use your own special character class, then you have
|
||
<a class="link" href="http://gcc.gnu.org/ml/libstdc++/2002-08/msg00163.html" target="_top">a lot
|
||
of work to do</a>, especially if you with to use i18n features
|
||
(facets require traits information but don't have a traits argument).
|
||
</p><p>Another example of how to specialize char_traits was given <a class="link" href="http://gcc.gnu.org/ml/libstdc++/2002-08/msg00260.html" target="_top">on the
|
||
mailing list</a> and at a later date was put into the file <code class="code">
|
||
include/ext/pod_char_traits.h</code>. We agree
|
||
that the way it's used with basic_string (scroll down to main())
|
||
doesn't look nice, but that's because <a class="link" href="http://gcc.gnu.org/ml/libstdc++/2002-08/msg00236.html" target="_top">the
|
||
nice-looking first attempt</a> turned out to <a class="link" href="http://gcc.gnu.org/ml/libstdc++/2002-08/msg00242.html" target="_top">not
|
||
be conforming C++</a>, due to the rule that CharT must be a POD.
|
||
(See how tricky this is?)
|
||
</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a id="strings.string.token"></a>Tokenizing</h3></div></div></div><p>
|
||
</p><p>The Standard C (and C++) function <code class="code">strtok()</code> leaves a lot to
|
||
be desired in terms of user-friendliness. It's unintuitive, it
|
||
destroys the character string on which it operates, and it requires
|
||
you to handle all the memory problems. But it does let the client
|
||
code decide what to use to break the string into pieces; it allows
|
||
you to choose the "whitespace," so to speak.
|
||
</p><p>A C++ implementation lets us keep the good things and fix those
|
||
annoyances. The implementation here is more intuitive (you only
|
||
call it once, not in a loop with varying argument), it does not
|
||
affect the original string at all, and all the memory allocation
|
||
is handled for you.
|
||
</p><p>It's called stringtok, and it's a template function. Sources are
|
||
as below, in a less-portable form than it could be, to keep this
|
||
example simple (for example, see the comments on what kind of
|
||
string it will accept).
|
||
</p><pre class="programlisting">
|
||
#include <string>
|
||
template <typename Container>
|
||
void
|
||
stringtok(Container &container, string const &in,
|
||
const char * const delimiters = " \t\n")
|
||
{
|
||
const string::size_type len = in.length();
|
||
string::size_type i = 0;
|
||
|
||
while (i < len)
|
||
{
|
||
// Eat leading whitespace
|
||
i = in.find_first_not_of(delimiters, i);
|
||
if (i == string::npos)
|
||
return; // Nothing left but white space
|
||
|
||
// Find the end of the token
|
||
string::size_type j = in.find_first_of(delimiters, i);
|
||
|
||
// Push token
|
||
if (j == string::npos)
|
||
{
|
||
container.push_back(in.substr(i));
|
||
return;
|
||
}
|
||
else
|
||
container.push_back(in.substr(i, j-i));
|
||
|
||
// Set up for next loop
|
||
i = j + 1;
|
||
}
|
||
}
|
||
</pre><p>
|
||
The author uses a more general (but less readable) form of it for
|
||
parsing command strings and the like. If you compiled and ran this
|
||
code using it:
|
||
</p><pre class="programlisting">
|
||
std::list<string> ls;
|
||
stringtok (ls, " this \t is\t\n a test ");
|
||
for (std::list<string>const_iterator i = ls.begin();
|
||
i != ls.end(); ++i)
|
||
{
|
||
std::cerr << ':' << (*i) << ":\n";
|
||
} </pre><p>You would see this as output:
|
||
</p><pre class="programlisting">
|
||
:this:
|
||
:is:
|
||
:a:
|
||
:test: </pre><p>with all the whitespace removed. The original <code class="code">s</code> is still
|
||
available for use, <code class="code">ls</code> will clean up after itself, and
|
||
<code class="code">ls.size()</code> will return how many tokens there were.
|
||
</p><p>As always, there is a price paid here, in that stringtok is not
|
||
as fast as strtok. The other benefits usually outweigh that, however.
|
||
</p><p><span class="emphasis"><em>Added February 2001:</em></span> Mark Wilden pointed out that the
|
||
standard <code class="code">std::getline()</code> function can be used with standard
|
||
<code class="code">istringstreams</code> to perform
|
||
tokenizing as well. Build an istringstream from the input text,
|
||
and then use std::getline with varying delimiters (the three-argument
|
||
signature) to extract tokens into a string.
|
||
</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a id="strings.string.shrink"></a>Shrink to Fit</h3></div></div></div><p>
|
||
</p><p>From GCC 3.4 calling <code class="code">s.reserve(res)</code> on a
|
||
<code class="code">string s</code> with <code class="code">res < s.capacity()</code> will
|
||
reduce the string's capacity to <code class="code">std::max(s.size(), res)</code>.
|
||
</p><p>This behaviour is suggested, but not required by the standard. Prior
|
||
to GCC 3.4 the following alternative can be used instead
|
||
</p><pre class="programlisting">
|
||
std::string(str.data(), str.size()).swap(str);
|
||
</pre><p>This is similar to the idiom for reducing
|
||
a <code class="code">vector</code>'s memory usage
|
||
(see <a class="link" href="../faq.html#faq.size_equals_capacity" title="7.8.">this FAQ
|
||
entry</a>) but the regular copy constructor cannot be used
|
||
because libstdc++'s <code class="code">string</code> is Copy-On-Write in GCC 3.
|
||
</p><p>In <a class="link" href="status.html#status.iso.2011" title="C++ 2011">C++11</a> mode you can call
|
||
<code class="code">s.shrink_to_fit()</code> to achieve the same effect as
|
||
<code class="code">s.reserve(s.size())</code>.
|
||
</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a id="strings.string.Cstring"></a>CString (MFC)</h3></div></div></div><p>
|
||
</p><p>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.
|
||
</p><p>Things are not as bad as they seem. In
|
||
<a class="link" href="http://gcc.gnu.org/ml/gcc/1999-04n/msg00236.html" target="_top">this
|
||
message</a>, Joe Buck points out a few very important things:
|
||
</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><p>The Standard <code class="code">string</code> supports all the operations
|
||
that CString does, with three exceptions.
|
||
</p></li><li class="listitem"><p>Two of those exceptions (whitespace trimming and case
|
||
conversion) are trivial to implement. In fact, we do so
|
||
on this page.
|
||
</p></li><li class="listitem"><p>The third is <code class="code">CString::Format</code>, which allows formatting
|
||
in the style of <code class="code">sprintf</code>. This deserves some mention:
|
||
</p></li></ul></div><p>
|
||
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:
|
||
</p><pre class="programlisting">
|
||
#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();
|
||
} </pre><p>A serious problem with CString is a design bug in its memory
|
||
allocation. Specifically, quoting from that same message:
|
||
</p><pre class="programlisting">
|
||
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).
|
||
</pre><p>Joe Buck also pointed out some other things to keep in mind when
|
||
comparing CString and the Standard string class:
|
||
</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><p>CString permits access to its internal representation; coders
|
||
who exploited that may have problems moving to <code class="code">string</code>.
|
||
</p></li><li class="listitem"><p>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.
|
||
<span class="emphasis"><em><span class="emphasis"><em>Note:</em></span> 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.</em></span>
|
||
</p></li><li class="listitem"><p><code class="code">string</code> operations like this have O(n) complexity
|
||
<span class="emphasis"><em>if the implementors do it correctly</em></span>. The libstdc++
|
||
implementors did it correctly. Other vendors might not.
|
||
</p></li><li class="listitem"><p>While parts of the SGI STL are used in libstdc++, their
|
||
string class is not. The SGI <code class="code">string</code> is essentially
|
||
<code class="code">vector<char></code> 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?)
|
||
</p></li></ul></div></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="traits.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="std_contents.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="localization.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Traits </td><td width="20%" align="center"><a accesskey="h" href="../index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 8.
|
||
Localization
|
||
|
||
</td></tr></table></div></body></html> |