Tải bản đầy đủ (.pdf) (37 trang)

Thinking in C++ 2nd edition Volume 2 Standard Libraries & Advanced Topics revision 1 phần 1 pps

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (170.99 KB, 37 trang )


Thinking in C++ 2
nd
edition
Volume 2: Standard Libraries &
Advanced Topics
To be informed of future releases of this document and other information about object-
oriented books, documents, seminars and CDs, subscribe to my free newsletter. Just send any
email to:

________________________________________________________________________

“This book is a tremendous achievement. You owe it to yourself to have a
copy on your shelf. The chapter on iostreams is the most comprehensive and
understandable treatment of that subject I’ve seen to date.”
Al Stevens
Contributing Editor, Doctor Dobbs Journal

“Eckel’s book is the only one to so clearly explain how to rethink program
construction for object orientation. That the book is also an excellent tutorial
on the ins and outs of C++ is an added bonus.”
Andrew Binstock
Editor, Unix Review

“Bruce continues to amaze me with his insight into C++, and
Thinking in
C++
is his best collection of ideas yet. If you want clear answers to difficult
questions about C++, buy this outstanding book.”
Gary Entsminger
Author, The Tao of Objects




Thinking in C++
patiently and methodically explores the issues of when and
how to use inlines, references, operator overloading, inheritance and dynamic
objects, as well as advanced topics such as the proper use of templates,
exceptions and multiple inheritance. The entire effort is woven in a fabric that
includes Eckel’s own philosophy of object and program design. A must for
every C++ developer’s bookshelf,
Thinking in C++
is the one C++ book you
must have if you’re doing serious development with C++.”
Richard Hale Shaw
Contributing Editor, PC Magazine


Thinking
In
C++
2
nd
Edition, Volume 2
Bruce Eckel

President, MindView Inc.



© 1999 by Bruce Eckel, MindView, Inc.


The information in this book is distributed on an “as is” basis, without warranty. While
every precaution has been taken in the preparation of this book, neither the author nor the
publisher shall have any liability to any person or entitle with respect to any liability, loss or damage
caused or alleged to be caused directly or indirectly by instructions contained in this book or by the
computer software or hardware products described herein.
All rights reserved. No part of this book may be reproduced in any form or by any electronic or
mechanical means including information storage and retrieval systems without permission in writing
from the publisher or author, except by a reviewer who may quote brief passages in a review. Any of the
names used in the examples and text of this book are fictional; any relationship to persons living or dead
or to fictional characters in other works is purely coincidental.

dedication
To the scholar, the healer, and the muse


What’s inside
Thinking in C++ 2
nd
edition Volume 2: Standard Libraries & Advanced Topics Revision 1, xx 1999
1
Preface 13
What’s new in the second edition13
What’s in Volume 2 of this book 14
How to get Volume 2 14
Prerequisites 14
Learning C++ 14
Goals 16
Chapters 17
Exercises 18
Exercise solutions 18

Source code 18
Language standards 20
Language support 20
The book’s CD ROM 20
Seminars, CD Roms & consulting20
Errors 21
Acknowledgements 21
Part 1: The Standard C++ Library 23
Library overview 24
1: Strings 27
What’s in a string 27
Creating and initializing C++ strings 29
Operating on strings 31
Appending, inserting and concatenating strings 32
Replacing string characters 34
Concatenation using non-member overloaded operators 37
Searching in strings 38
Finding in reverse 43
Finding first/last of a set 44
Removing characters from strings 45
Comparing strings 49
Using iterators 53
Chapter 2: Hiding the Implementation 7
Strings and character traits 55
A string application 58
Summary 61
Exercises 62
2: Iostreams 63
Why iostreams? 63
True wrapping 65

Iostreams to the rescue 67
Sneak preview of operator overloading68
Inserters and extractors 69
Common usage 70
Line-oriented input 72
File iostreams 74
Open modes 76
Iostream buffering 76
Using
get( )
with a streambuf 78
Seeking in iostreams 78
Creating read/write files 80
stringstreams 81
strstreams 81
User-allocated storage 81
Automatic storage allocation 84
Output stream formatting 87
Internal formatting data 88
An exhaustive example 92
Formatting manipulators 95
Manipulators with arguments 96
Creating manipulators 99
Effectors 100
Iostream examples 102
Code generation 102
A simple datalogger 110
Counting editor 117
Breaking up big files 118
Summary 120

Exercises 120
3: Templates in depth 121
Nontype template arguments 121
Default template arguments 122
The typename keyword 122
Typedefing a typename 124
Using
typename
instead of
class
124
Function templates 124
A string conversion system 125
A memory allocation system 126
Type induction in function templates 129
Taking the address of a generated function template 130
Chapter 2: Hiding the Implementation 8
Local classes in templates 131
Applying a function to an STL sequence 131
Template-templates 134
Member function templates 135
Why virtual member template functions are disallowed 137
Nested template classes 137
Template specializations 137
Full specialization 137
Partial Specialization 137
A practical example 137
Design & efficiency 141
Preventing template bloat 141
Explicit instantiation 143

Explicit specification of template functions 144
Controlling template instantiation144
The inclusion vs. separation models145
The export keyword 145
Template programming idioms 145
The “curiously-recurring template”.145
Traits 145
Summary 145
4: STL Containers & Iterators147
Containers and iterators 147
STL reference documentation 149
The Standard Template Library149
The basic concepts 151
Containers of strings 155
Inheriting from STL containers 157
A plethora of iterators 159
Iterators in reversible containers 161
Iterator categories 162
Predefined iterators 163
Basic sequences: vector, list & deque 169
Basic sequence operations 169
vector 172
Cost of overflowing allocated storage173
Inserting and erasing elements 177
deque 179
Converting between sequences 181
Cost of overflowing allocated storage182
Checked random-access 184
list 185
Special list operations 187

Swapping all basic sequences 191
Robustness of lists 192
Performance comparison 193
set 198
Eliminating
strtok( )
199
StreamTokenizer
: a more flexible solution 201
Chapter 2: Hiding the Implementation 9
A completely reusable tokenizer 203
stack 208
queue 211
Priority queues 216
Holding bits 226
bitset<n>
226
vector<bool>
230
Associative containers 232
Generators and fillers for associative containers 236
The magic of maps 239
Multimaps and duplicate keys 244
Multisets 247
Combining STL containers 250
Cleaning up containers of pointers253
Creating your own containers 255
Freely-available STL extensions257
Summary 259
Exercises 260

5: STL Algorithms 263
Function objects 263
Classification of function objects 264
Automatic creation of function objects265
SGI extensions 279
A catalog of STL algorithms 285
Support tools for example creation 287
Filling & generating 291
Counting 293
Manipulating sequences 294
Searching & replacing 299
Comparing ranges 305
Removing elements 308
Sorting and operations on sorted ranges311
Heap operations 322
Applying an operation to each element in a range 323
Numeric algorithms 331
General utilities 334
Creating your own STL-style algorithms 336
Summary 337
Exercises 337
Part 2: Advanced Topics 341
6: Multiple inheritance 342
Perspective 342
Duplicate subobjects 344
Ambiguous upcasting 345
virtual
base classes 346
Chapter 2: Hiding the Implementation 10
The "most derived" class and virtual base initialization 348

"Tying off" virtual bases with a default constructor 349
Overhead 351
Upcasting 352
Persistence 355
Avoiding MI 362
Repairing an interface 362
Summary 367
Exercises 368
7: Exception handling 369
Error handling in C 369
Throwing an exception 372
Catching an exception 373
The
try
block 373
Exception handlers 373
The exception specification 374
Better exception specifications? 377
Catching any exception 377
Rethrowing an exception 378
Uncaught exceptions 378
Function-level try blocks 380
Cleaning up 380
Constructors 384
Making everything an object 386
Exception matching 388
Standard exceptions 390
Programming with exceptions . 391
When to avoid exceptions 391
Typical uses of exceptions 392

Overhead 396
Summary 397
Exercises 397
8: Run-time type identification399
The “Shape” example 399
What is RTTI? 400
Two syntaxes for RTTI 400
Syntax specifics 404
typeid( )
with built-in types 404
Producing the proper type name 405
Nonpolymorphic types 405
Casting to intermediate levels 406
void
pointers 408
Using RTTI with templates 408
References 409
Exceptions 410
Multiple inheritance 411
Chapter 2: Hiding the Implementation 11
Sensible uses for RTTI 412
Revisiting the trash recycler 413
Mechanism & overhead of RTTI416
Creating your own RTTI 416
Explicit cast syntax 420
Summary 421
Exercises 422
9: Building stable systems 423
Shared objects & reference counting 423
Reference-counted class hierarchies423

The canonical object & singly-rooted hierarchies 423
An extended canonical form 424
Design by contract 424
Integrated unit testing 424
Dynamic aggregation 424
Exercises 428
10: Design patterns 429
The pattern concept 429
The singleton 430
Classifying patterns 434
Features, idioms, patterns 435
Basic complexity hiding 435
Factories: encapsulating object creation 436
Polymorphic factories 438
Abstract factories 441
Virtual constructors 444
Callbacks 449
Functor/Command 450
Strategy 450
Observer 450
Multiple dispatching 459
Visitor, a type of multiple dispatching463
Efficiency 466
Flyweight 466
The composite 466
Evolving a design: the trash recycler 466
Improving the design 471
“Make more objects” 471
A pattern for prototyping creation 476
Abstracting usage 488

Applying double dispatching 492
Implementing the double dispatch 492
Applying the visitor pattern 497
RTTI considered harmful? 503
Summary 506
Chapter 2: Hiding the Implementation 12
Exercises 507
11: Tools & topics 509
The code extractor 509
Debugging 531
assert( )
531
Trace macros 531
Trace file 532
Abstract base class for debugging 533
Tracking
new
/
delete
&
malloc
/
free
533
CGI programming in C++ 539
Encoding data for CGI 540
The CGI parser 541
Using POST 548
Handling mailing lists 549
A general information-extraction CGI program 560

Parsing the data files 566
Summary 573
Exercises 573
A: Recommended reading 575
C 575
General C++ 575
My own list of books 576
Depth & dark corners 576
The STL 576
Design Patterns 576
B:Compiler specifics 577
Index 580

Preface 15
and other “sophisticated” concepts, scuttling away in shame when the subjects came up in
conversation rather than reaching out for new knowledge.
When I began my struggle to understand C++, the only decent book was Stroustrup’s self-
professed “expert’s guide,
1
” so I was left to simplify the basic concepts on my own. This
resulted in my first C++ book,
2
which was essentially a brain dump of my experience. That
was designed as a reader’s guide, to bring programmers into C and C++ at the same time.
Both editions
3
of the book garnered an enthusiastic response.
At about the same time that
Using C++
came out, I began teaching the language in live

seminars and presentations. Teaching C++ (and later, Java) became my profession; I’ve seen
nodding heads, blank faces, and puzzled expressions in audiences all over the world since
1989. As I began giving in-house training with smaller groups of people, I discovered
something during the exercises. Even those people who were smiling and nodding were
confused about many issues. I found out, by creating and chairing the C++ and Java tracks at
the Software Development Conference for many years, that I and other speakers tended to
give the typical audience too many topics, too fast. So eventually, through both variety in the
audience level and the way that I presented the material, I would end up losing some portion
of the audience. Maybe it’s asking too much, but because I am one of those people resistant to
traditional lecturing (and for most people, I believe, such resistance results from boredom), I
wanted to try to keep everyone up to speed.
For a time, I was creating a number of different presentations in fairly short order. Thus, I
ended up learning by experiment and iteration (a technique that also works well in C++
program design). Eventually I developed a course using everything I had learned from my
teaching experience. It tackles the learning problem in discrete, easy-to-digest steps and for a
hands-on seminar (the ideal learning situation), there are exercises following each of the
presentations.
The first edition of this book developed over the course of two

years, and the material in this
book has been road-tested in many forms in many different seminars. The feedback that I’ve
gotten from each seminar has helped me change and refocus the material until I feel it works
well as a teaching medium. But it isn’t just a seminar handout – I tried to pack as much
information as I could within these pages, and structure it to draw you through, onto the next
subject. More than anything, the book is designed to serve the solitary reader, struggling with
a new programming language.


1
Bjarne Stroustrup,

The C++ Programming Language
, Addison-Wesley, 1986 (first edition).
2

Using C++
,

Osborne/McGraw-Hill 1989.
3

Using C++
and
C++ Inside & Out
,

Osborne/McGraw-Hill 1993.
Preface 19
site. The program will create a directory for each chapter and unpack the code into those
directories. In the starting directory where you unpacked the code you will find the following
copyright notice:
//:! :CopyRight.txt
Copyright (c) Bruce Eckel, 1999
Source code file from the book "Thinking in C++"
All rights reserved EXCEPT as allowed by the
following statements: You can freely use this file
for your own work (personal or commercial),
including modifications and distribution in
executable form only. Permission is granted to use
this file in classroom situations, including its
use in presentation materials, as long as the book

"Thinking in C++" is cited as the source.
Except in classroom situations, you cannot copy
and distribute this code; instead, the sole
distribution point is
(and official mirror sites) where it is
freely available. You cannot remove this
copyright and notice. You cannot distribute
modified versions of the source code in this
package. You cannot use this file in printed
media without the express permission of the
author. Bruce Eckel makes no representation about
the suitability of this software for any purpose.
It is provided "as is" without express or implied
warranty of any kind, including any implied
warranty of merchantability, fitness for a
particular purpose or non-infringement. The entire
risk as to the quality and performance of the
software is with you. Bruce Eckel and the
publisher shall not be liable for any damages
suffered by you or any third party as a result of
using or distributing software. In no event will
Bruce Eckel or the publisher be liable for any
lost revenue, profit, or data, or for direct,
indirect, special, consequential, incidental, or
punitive damages, however caused and regardless of
the theory of liability, arising out of the use of
or inability to use software, even if Bruce Eckel
and the publisher have been advised of the
possibility of such damages. Should the software
prove defective, you assume the cost of all

Preface 22
The Cranstons, Larry Fogg, Mike & Karen Sequeira, Gary Entsminger & Allison Brody,
Chester Andersen, Joe Lordi, Dave & Brenda Bartlett, The Rentschlers, The Sudeks, Lynn &
Todd, and their families. And of course, Mom & Dad.
Chapter 14: Templates & Container Classes
25
Localization Library
. This allows you to localize strings in your program to adapt to usage
in different countries, including money, numbers, date, time, and so on.
Containers Library
. This includes the Standard Template Library (described in the next
section of this appendix) and also the
bits
and
bit_string
classes in
<bits>
and
<bitstring>
,
respectively. Both
bits
and
bit_string
are more complete implementations of the bitvector
concept introduced in Chapter XX. The
bits
template creates a fixed-sized array of bits that
can be manipulated with all the bitwise operators, as well as member functions like
set( )

,
reset( )
,
count( )
,
length( )
,
test( )
,
any( )
, and
none( )
. There are also conversion operators
to_ushort( )
,
to_ulong( )
, and
to_string( )
.
The
bit_string
class is, by contrast, a dynamically sized array of bits, with similar operations
to
bits
, but also with additional operations that make it act somewhat like a
string
. There’s a
fundamental difference in bit weighting: With
bits
, the right-most bit (bit zero) is the least

significant bit, but with
bit_string
, the right-most bit is the
most
significant bit. There are no
conversions between
bits
and
bit_string
. You’ll use
bits
for a space-efficient set of on-off
flags and
bit_string
for manipulating arrays of binary values (like pixels).
Iterators Library
. Includes iterators that are tools for the STL (described in the next section
of this appendix), streams, and stream buffers.
Algorithms Library
. These are the template functions that perform operations on the STL
containers using iterators. The algorithms include:
adjacent_find
,
prev_permutation
,

binary_search
,
push_heap
,

copy
,
random_shuffle
,
copy_backward
,
remove
,
count
,

remove_copy
,
count_if
,
remove_copy_if
,
equal
,
remove_if
,
equal_range
,
replace
,
fill
,

replace_copy
,

fill_n
,
replace_copy_if
,
find
,
replace_if
,
find_if
,
reverse
,
for_each
,

reverse_copy
,
generate
,
rotate
,
generate_n
,
rotate_copy
,
includes
,
search
,


inplace_merge
,
set_difference
,
lexicographical_compare
,
set_intersection
,
lower_bound
,

set_symmetric_difference
,
make_heap
,
set_union
,
max
,
sort
,
max_element
,
sort_heap
,

merge
,
stable_partition
,

min
,
stable_sort
,
min_element
,
swap
,
mismatch
,
swap_ranges
,

next_permutation
,
transform
,
nth_element
,
unique
,
partial_sort
,
unique_copy
,

partial_sort_copy
,
upper_bound
, and

partition
.

Numerics Library
. The goal of this library is to allow the compiler implementer to take
advantage of the architecture of the underlying machine when used for numerical operations.
This way, creators of higher level numerical libraries can write to the numerics library and
produce efficient algorithms without having to customize to every possible machine. The
numerics library also includes the complex number class (which appeared in the first version
of C++ as an example, and has become an expected part of the library) in
float
,
double
, and
long double
forms.

Chapter 14: Templates & Container Classes
28
C++
string
s and their C progenitors. First, C++
string
objects associate the array of
characters which constitute the
string
with methods useful for managing and operating on it.
A
string
also contains certain “housekeeping” information about the size and storage location

of its data. Specifically, a C++
string
object knows its starting location in memory, its
content, its length in characters, and the length in characters to which it can grow before the
string
object must resize its internal data buffer. This gives rise to the second big difference
between C
char
arrays and C++
string
s. C++
string
s do not include a null terminator, nor do
the C++
string
handling member functions rely on the existence of a null terminator to
perform their jobs. C++
string
s greatly reduce the likelihood of making three of the most
common and destructive C programming errors: overwriting array bounds, trying to access
arrays through uninitialized or incorrectly valued pointers, and leaving pointers “dangling”
after an array ceases to occupy the storage that was once allocated to it.
The exact implementation of memory layout for the string class is not defined by the C++
Standard. This architecture is intended to be flexible enough to allow differing
implementations by compiler vendors, yet guarantee predictable behavior for users. In
particular, the exact conditions under which storage is allocated to hold data for a string object
are not defined. String allocation rules were formulated to allow but not require a reference-
counted implementation, but whether or not the implementation uses reference counting, the
semantics must be the same. To put this a bit differently, in C, every
char

array occupies a
unique physical region of memory. In C++, individual
string
objects may or may not occupy
unique physical regions of memory, but if reference counting is used to avoid storing
duplicate copies of data, the individual objects must look and act as though they do
exclusively own unique regions of storage. For example:
//: C01:StringStorage.cpp
#include <string>
#include <iostream>
using namespace std;

int main() {
string s1("12345");
// Set the iterator indicate the first element
string::iterator it = s1.begin();
// This may copy the first to the second or
// use reference counting to simulate a copy
string s2 = s1;
// Either way, this statement may ONLY modify first
*it = '0';
cout << "s1 = " << s1 << endl;
cout << "s2 = " << s2 << endl;
} ///:~

Reference counting may serve to make an implementation more memory efficient, but it is
transparent to users of the
string
class.
Chapter 14: Templates & Container Classes

30

int main() {
string s1
("What is the sound of one clam napping?");
string s2
("Anything worth doing is worth overdoing.");
string s3("I saw Elvis in a UFO.");
// Copy the first 8 chars
string s4(s1, 0, 8);
// Copy 6 chars from the middle of the source
string s5(s2, 15, 6);
// Copy from middle to end
string s6(s3, 6, 15);
// Copy all sorts of stuff
string quoteMe = s4 + "that" +
// substr() copies 10 chars at element 20
s1.substr(20, 10) + s5 +
// substr() copies up to either 100 char
// or eos starting at element 5
"with" + s3.substr(5, 100) +
// OK to copy a single char this way
s1.substr(37, 1);
cout << quoteMe << endl;
} ///:~

The
string
member function
substr( )

takes a starting position as its first argument and the
number of characters to select as the second argument. Both of these arguments have default
values and if you say
substr( )
with an empty argument list you produce a copy of the entire
string
, so this is a convenient way to duplicate a
string
.
Here’s what the
string

quoteMe
contains after the initialization shown above :
"What is that one clam doing with Elvis in a UFO.?"

Notice the final line of example above. C++ allows
string
initialization techniques to be
mixed in a single statement, a flexible and convenient feature. Also note that the last
initializer copies
just one character
from the source
string
.
Another slightly more subtle initialization technique involves the use of the
string
iterators
string.begin( )
and

string.end( ).
This treats a
string
like a
container
object (which you’ve
seen primarily in the form of
vector
so far in this book – you’ll see many more containers
soon) which has
iterators
indicating the start and end of the “container.” This way you can
hand a
string
constructor two iterators and it will copy from one to the other into the new
string
:
//: C01:StringIterators.cpp
Chapter 14: Templates & Container Classes
33
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:
I saw Elvis in a UFO.
Size = 21
Capacity = 31
I thought I saw Elvis in a UFO.
Size = 32
Capacity = 63
I thought I saw Elvis in a UFO. I've been
working too hard.
Size = 66
Capacity = 511

This example demonstrates that even though you can safely relinquish much of the
responsibility for allocating and managing the memory your
string
s occupy, C++
string
s
provide you with several tools to monitor and manage their size. The
size( )
,
resize( )
,
capacity( )
, and
reserve( )
member functions can be very useful when its necessary to work

back and forth between data contained in C++ style strings and traditional null terminated C
char
arrays. Note the ease with which we changed the size of the storage allocated to the
string.
The exact fashion in which the
string
member functions will allocate space for your data is
dependent on the implementation of the library. When one implementation was tested with
the example above, it appeared that reallocations occurred on even word 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.
Chapter 14: Templates & Container Classes
35
string findMe, string newChars){
// Look in modifyMe for the "find string"
// starting at position 0
int i = modifyMe.find(findMe, 0);
// Did we find the string to replace?
if(i != string::npos)
// Replace the find string with newChars
modifyMe.replace(i,newChars.size(),newChars);
}


int main() {
string bigNews =
"I thought I saw Elvis in a UFO. "
"I have been working too hard.";
string replacement("wig");
string findMe("UFO");
// Find "UFO" in bigNews and overwrite it:
replaceChars(bigNews, findMe, replacement);
cout << bigNews << endl;
} ///:~

Now the last line of output from
replace.cpp
looks like this:
I thought I saw Elvis in a wig. I have been
working too hard.

If replace doesn’t find the search string, it returns
npos
.
npos
is a static constant member of
the
basic_string
class.
Unlike
insert( )
,
replace( )
won’t grow the

string
’s storage space if you copy new characters
into the middle of an existing series of array elements. However, it
will
grow the storage
space if you make a “replacement” that writes beyond the end of an existing array. Here’s an
example:
//: C01:ReplaceAndGrow.cpp
#include <string>
#include <iostream>
using namespace std;

int main() {
string bigNews("I saw Elvis in a UFO. "
"I have been working too hard.");
string replacement("wig");
// The first arg says "replace chars
// beyond the end of the existing string":
bigNews.replace(bigNews.size(),
Chapter 14: Templates & Container Classes
36
replacement.size(), replacement);
cout << bigNews << endl;
} ///:~

The call to
replace( )
begins “replacing” beyond the end of the existing array. The output
looks like this:
I saw Elvis in a UFO. I have

been working too hard.wig

Notice that
replace( )
expands the array to accommodate the growth of the string due to
“replacement” beyond the bounds of the existing array.
Simple character replacement using the STL
replace( ) algorithm
You may have been hunting through this chapter trying to do something relatively simple like
replace all the instances of one character with a different character. Upon finding the above
section on replacing, you thought you found the answer but then you started seeing groups of
characters and counts and other things that looked a bit too complex. Doesn’t
string
have a
way to just replace one character with another everywhere?
The
string
class by itself doesn’t solve all possible problems. The remainder are relegated to
the STL algorithms, because the
string
class can look just like an STL container (the STL
algorithms work with anything that looks like an STL container). All the STL algorithms
work on a “range” of elements within a container. Usually that range is just “from the
beginning of the container to the end.” A
string
object looks like a container of characters: to
get the beginning of the range you use
string::begin( )
and to get the end of the range you use
string::end( )

. The following example shows the use of the STL
replace( )
algorithm to
replace all the instances of ‘X’ with ‘Y’:
//: C01:StringCharReplace.cpp
#include <string>
#include <algorithm>
#include <iostream>
using namespace std;

int main() {
string s("aaaXaaaXXaaXXXaXXXXaaa");
cout << s << endl;
replace(s.begin(), s.end(), 'X', 'Y');
cout << s << endl;
} ///:~

Notice that this
replace( )
is
not
called as a member function of
string
. Also, unlike the
string::replace( )
functions which only perform one replacement, the STL replace is
replacing all instances of one character with another.
Chapter 14: Templates & Container Classes
39
The simplest use of

find( )
searches for one or more characters in a
string
. This overloaded
version of
find( )
takes a parameter that specifies the character(s) for which to search, and
optionally one that tells it where in the string to begin searching for the occurrence of a
substring. (The default position at which to begin searching is 0.) By setting the call to
find
inside a loop, you can easily move through a string, repeating a search in order to find all of
the occurrences of a given character or group of characters within the string.
Notice that we define the string object
sieveChars
using a constructor idiom which sets the
initial size of the character array and writes the value ‘P’ to each of its member.
//: C01:Sieve.cpp
#include <string>
#include <iostream>
using namespace std;

int main() {
// Create a 50 char string and set each
// element to 'P' for Prime
string sieveChars(50, 'P');
// By definition neither 0 nor 1 is prime.
// Change these elements to "N" for Not Prime
sieveChars.replace(0, 2, "NN");
// Walk through the array:
for(int i = 2;

i <= (sieveChars.size() / 2) - 1; i++)
// Find all the factors:
for(int factor = 2;
factor * i < sieveChars.size();factor++)
sieveChars[factor * i] = 'N';

cout << "Prime:" << endl;
// Return the index of the first 'P' element:
int j = sieveChars.find('P');
// While not at the end of the string:
while(j != sieveChars.npos) {
// If the element is P, the index is a prime
cout << j << " ";
// Move past the last prime
j++;
// Find the next prime
j = sieveChars.find('P', j);
}
cout << "\n Not prime:" << endl;
// Find the first element value not equal P:
Chapter 14: Templates & Container Classes
40
j = sieveChars.find_first_not_of('P');
while(j != sieveChars.npos) {
cout << j << " ";
j++;
j = sieveChars.find_first_not_of('P', j);
}
} ///:~


The output from
Sieve.cpp
looks like this:
Prime:
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47
Not prime:
0 1 4 6 8 9 10 12 14 15 16 18 20 21 22
24 25 26 27 28 30 32 33 34 35 36 38 39
40 42 44 45 46 48 49

find( )
allows you to walk forward through a
string
, detecting multiple occurrences of a
character or group of characters, while
find_first_not_of( )
allows you to test for the absence
of a character or group.
The
find
member is also useful for detecting the occurrence of a sequence of characters in a
string
:
//: C01:Find.cpp
// Find a group of characters in a string
#include <string>
#include <iostream>
using namespace std;

int main() {

string chooseOne("Eenie, meenie, miney, mo");
int i = chooseOne.find("een");
while(i != string::npos) {
cout << i << endl;
i++;
i = chooseOne.find("een", i);
}
} ///:~

Find.cpp
produces a single line of output :
8

This tells us that the first ‘e’ of the search group “een” was found in the word “meenie,” and
is the eighth element in the string. Notice that
find
passed over the “Een” group of characters
in the word “Eenie”. The
find
member function performs a
case sensitive
search.
Chapter 14: Templates & Container Classes
41
There are no functions in the
string
class to change the case of a string, but these functions
can be easily created using the Standard C library functions
toupper( )
and

tolower( )
, which
change the case of one character at a time. A few small changes will make
Find.cpp
perform
a case insensitive search:
//: C01:NewFind.cpp
#include <string>
#include <iostream>
using namespace std;

// Make an uppercase copy of s:
string upperCase(string& s) {
char* buf = new char[s.length()];
s.copy(buf, s.length());
for(int i = 0; i < s.length(); i++)
buf[i] = toupper(buf[i]);
string r(buf, s.length());
delete buf;
return r;
}

// Make a lowercase copy of s:
string lowerCase(string& s) {
char* buf = new char[s.length()];
s.copy(buf, s.length());
for(int i = 0; i < s.length(); i++)
buf[i] = tolower(buf[i]);
string r(buf, s.length());
delete buf;

return r;
}

int main() {
string chooseOne("Eenie, meenie, miney, mo");
cout << chooseOne << endl;
cout << upperCase(chooseOne) << endl;
cout << lowerCase(chooseOne) << endl;
// Case sensitive search
int i = chooseOne.find("een");
while(i != string::npos) {
cout << i << endl;
i++;
i = chooseOne.find("een", i);
}

×