assert(first.compare(1, 7, second, 22, 7) == 0);

  // Compare "his is a" to "his is w":

  assert(first.compare(1, 9, second, 22, 9) < 0);

} ///:~

In the examples so far, we have used C-style array indexing syntax to refer to an individual character in a string. C++ strings provide an alternative to the s[n] notation: the at( ) member. These two indexing mechanisms produce the same result in C++ if all goes well:.

//: C03:StringIndexing.cpp

#include

#include

using namespace std;

int main(){

  string s("1234");

  assert(s[1] == '2');

  assert(s.at(1) == '2');

} ///:~

There is one important difference, however, between [ ] and at( ). When you try to reference an array element that is out of bounds, at( ) will do you the kindness of throwing an exception, while ordinary [ ] subscripting syntax will leave you to your own devices:.

//: C03:BadStringIndexing.cpp

#include

#include

#include

using namespace std;

int main(){

  string s("1234");

  // at() saves you by throwing an exception:

  try {

    s.at(5);

  } catch(exception& e) {

    cerr << e.what() << endl;

  }

} ///:~

Responsible programmers will not use errant indexes, but should you want to benefits of automatic index checking, using at( ) in place of [ ] will give you a chance to gracefully recover from references to array elements that don’t exist. Execution of this program on one of our test compilers gave the following output:

invalid string position

The at( ) member throws an object of class out_of_range, which derives (ultimately) from std::exception. By catching this object in an exception handler, you can take appropriate remedial actions such as recalculating the offending subscript or growing the array. Using string::operator[]( ) gives no such protection and is as dangerous as char array processing in C.[34] 

<p>Strings and character traits</p>

The program Find.cpp earlier in this chapter leads us to ask the obvious question: Why isn’t case-insensitive comparison part of the standard string class? The answer provides interesting background on the true nature of C++ string objects.

Consider what it means for a character to have "case." Written Hebrew, Farsi, and Kanji don’t use the concept of upper- and lowercase, so for those languages this idea has no meaning. It would seem that if there were a way to designate some languages as "all uppercase" or "all lowercase," we could design a generalized solution. However, some languages that employ the concept of "case" also change the meaning of particular characters with diacritical marks: for example, the cedilla in Spanish, the circumflex in French, and the umlaut in German. For this reason, any case-sensitive collating scheme that attempts to be comprehensive will be nightmarishly complex to use.

Although we usually treat the C++ string as a class, this is really not the case. The string type is actually a specialization of a more general constituent, the basic_string< > template. Observe how string is declared in the standard C++ header file:[35] 

typedef basic_string string;

To really understand the nature of the string class, it’s helpful to delve a bit deeper and look at the template on which it is based. Here’s the declaration of the basic_string< > template:.

Перейти на страницу:

Похожие книги