Выбрать главу

//: C03:UhOh.cpp

#include <string>

#include <cassert>

using namespace std;

int main() {

  // Error: no single char inits

  //! string nothingDoing1('a');

  // Error: no integer inits

  //! string nothingDoing2(0x37);

  // The following is legaclass="underline"

  string okay(5, 'a');

  assert(okay == string("aaaaa"));

} ///:~

Operating on strings

If you’ve programmed in C, you are accustomed to the convenience of a large family of functions for writing, searching, modifying, and copying char arrays. However, there are two unfortunate aspects of the Standard C library functions for handling char arrays. First, there are two loosely organized families of them: the "plain" group, and the ones that require you to supply a count of the number of characters to be considered in the operation at hand. The roster of functions in the C char array handling library shocks the unsuspecting user with a long list of cryptic, mostly unpronounceable names. Although the kinds and number of arguments to the functions are somewhat consistent, to use them properly you must be attentive to details of function naming and parameter passing.

The second inherent trap of the standard C char array tools is that they all rely explicitly on the assumption that the character array includes a null terminator. If by oversight or error the null is omitted or overwritten, there’s little to keep the C char array handling functions from manipulating the memory beyond the limits of the allocated space, sometimes with disastrous results.

C++ provides a vast improvement in the convenience and safety of string objects. For purposes of actual string handling operations, there are about the same number of distinct member function names in the string class as there are functions in the C library, but because of overloading there is much more functionality. Coupled with sensible naming practices and the judicious use of default arguments, these features combine to make the string class much easier to use than the C library.

Appending, inserting, and concatenating strings

One of the most valuable and convenient aspects of C++ strings is that they grow as needed, without intervention on the part of the programmer. Not only does this make string-handling code inherently more trustworthy, it also almost entirely eliminates a tedious "housekeeping" chore—keeping track of the bounds of the storage in which your strings live. For example, if you create a string object and initialize it with a string of 50 copies of ‘X’, and later store in it 50 copies of "Zowie", the object itself will reallocate sufficient storage to accommodate the growth of the data. Perhaps nowhere is this property more appreciated than when the strings manipulated in your code change size and you don’t know how big the change is. Appending, concatenating, and inserting strings often give rise to this circumstance, but the string member functions append( ) and insert( ) transparently reallocate storage when a string grows.

//: C03:StrSize.cpp

#include <string>

#include <iostream>

using namespace std;

int main() {

  string bigNews("I saw Elvis in a UFO. ");

  cout << bigNews << endl;

  // How much data have we actually got?

  cout << "Size = " << bigNews.size() << endl;

  // How much can we store without reallocating

  cout << "Capacity = "

    << bigNews.capacity() << endl;

  // Insert this string in bigNews immediately

  // before bigNews[1]

  bigNews.insert(1, " thought I");

  cout << bigNews << endl;

  cout << "Size = " << bigNews.size() << endl;

  cout << "Capacity = "

    << bigNews.capacity() << endl;

  // Make sure that there will be this much space

  bigNews.reserve(500);

  // Add this to the end of the string

  bigNews.append("I've been working too hard.");

  cout << bigNews << endl;

  cout << "Size = " << bigNews.size() << endl;

  cout << "Capacity = "

    << bigNews.capacity() << endl;

} ///:~

Here is the output from one particular compiler:.

I saw Elvis in a UFO.

Size = 22

Capacity = 31

I thought I saw Elvis in a UFO.

Size = 32

Capacity = 47

I thought I saw Elvis in a UFO. I've been

working too hard.

Size = 59

Capacity = 511

This example demonstrates that even though you can safely relinquish much of the responsibility for allocating and managing the memory your strings occupy, C++ strings provide you with several tools to monitor and manage their size. Notice the ease with which we changed the size of the storage allocated to the string. The size( ) function, of course, returns the number of characters currently stored in the string and is identical to the length( ) member function. The capacity( ) function returns the size of the current underlying allocation, meaning the number of characters the string can hold without requesting more storage. The reserve( ) function is an optimization mechanism that allows you to indicate your intention to specify a certain amount of storage for future use; capacity( ) always returns a value at least as large as the most recent call to reserve( ). A resize( ) function appends spaces if the new size is greater than the current string size or truncates the string otherwise. (An overload of resize( ) allows you to specify a different character to append.).

The exact fashion in which the string member functions allocate space for your data depends on the implementation of the library. When we tested one implementation with the previous example, it appeared that reallocations occurred on even word (that is, full-integer) boundaries, with one byte held back. The architects of the string class have endeavored to make it possible to mix the use of C char arrays and C++ string objects, so it is likely that figures reported by StrSize.cpp for capacity reflect that, in this particular implementation, a byte is set aside to easily accommodate the insertion of a null terminator.

Replacing string characters

The insert( ) function is particularly nice because it absolves you of making sure the insertion of characters in a string won’t overrun the storage space or overwrite the characters immediately following the insertion point. Space grows, and existing characters politely move over to accommodate the new elements. Sometimes, however, this might not be what you want to happen. If you want the size of the string to remain unchanged, use the replace( ) function to overwrite characters. There are quite a number of overloaded versions of replace( ), but the simplest one takes three arguments: an integer indicating where to start in the string, an integer indicating how many characters to eliminate from the original string, and the replacement string (which can be a different number of characters than the eliminated quantity). Here’s a simple example:.