You are on page 1of 522

class FunctionBase { public: /* Polymorphic classes need virtual destructors.

*/ virtual ~FunctionBase() {}

})

/* *emplate derived class that e#ecutes a speci!ic type o! !unction. */ template +typename ,naryFunction- class Function.mpl: public FunctionBase { public: e#plicit Function.mpl(,naryFunction !n) : !n(!n) {} virtual "et e#ecute(const $r%& val) { return !n(val)) } virtual Function.mpl* clone() const { return ne/ Function.mpl(*this)) } ,naryFunction !n) })

CS106L
/* alls the stored !unction. */ virtual "et e#ecute(const $r%& val) ' () virtual FunctionBase* clone() const ' ()

Standard C++ Programming Laboratory

Course Reader Fall 2010

Keith Schwarz Stanford University

Acknowledgements

_________________________________________________________________________________________________________

This course reader represents the culmination of two years' work on CS106 and its course handouts! "either the class nor this reader would have #een possi#le without $ulie %elenski's support and &enerosity durin& CS106 's infancy! ' stron&ly encoura&e you to take one of $ulie's classes ( you will not #e disappointed! ''d also like to e)tend thanks to all of the CS106 students ''ve had the pleasure of teachin& over the years! 't is truly a *oy to watch students li&ht up when they see e)actly what C++ can do! The lon& hours that went into this course reader would not have #een possi#le without the knowled&e that students are &enuinely interested in the material! ,dditionally- ' would like to thank the #rave souls who were &enerous enou&h to proofread draft versions of this course reader! .in /uan& and Steven 0u offered particularly apt advice on style and &rammar! 'lya Sherman &ave wonderful su&&estions on typesettin& and layout and cau&ht many errors that slipped under my radar! Kyle Knutson helped dou#le1check the correctness of the code in the e)tended e)amples! 2avid 3old#latt helped me stay on top of recent developments in C++0) and pointed out how to make many of the ST practice pro#lems truer to the spirit of the li#rary! Sam Schrei#er provided e)cellent advice a#out the overall structure of the reader and was the inspiration for the 4Criti5uin& Class 2esi&n6 chapter! eonid Shamis astutely su&&ested that ' e)pand the section on development environments! 7rittney 8raser's amazin& feed#ack made many of the e)amples easier to understand and prevented several ma*or errors from makin& it into this reader! This is the third edition of this course reader! There are certainly layout pro#lems- typoz- &rammatically errorsand spelin& misstakes that have made it into this version! 'f you have any comments- corrections- or su&&estions- please send me an email at htiek9cs!stanford!edu! This course reader and its contents- e)cept for 5uotations from other sources- are all : ;00< ( ;010 Keith Schwarz! 'f you would like to copy this course reader or its contents- send me an email and ''d #e &lad to see how ' can help out!

Introduction.................................................................................................................................................................... 1 Chapter 0= 0hat is C++>!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ? Chapter 1= 3ettin& Started!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 11 Chapter ;= C++ 0ithout &enli#!h!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 1< A Better C....................................................................................................................................................................... 23 Chapter @= Streams!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ;? Chapter A= Bulti18ile Cro&rams- ,#straction- and the Creprocessor!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!AD Chapter ?= ST Se5uence Containers!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! D< Chapter 6= ST ,ssociative Containers and 'terators!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 1;1 Chapter D= ST ,l&orithms!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 1D? Chapter E= C Strin&s!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ;0@ Data Abstraction....................................................................................................................................................... 217 Chapter <= ,#straction and Classes!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ;1< Chapter 10= Fefinin& ,#stractions!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ;?D Chapter 11= Gperator Gverloadin&!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! @1< Chapter 1;= Fesource Bana&ement!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! @6@ eneric !rogramming............................................................................................................................................. 3"# Chapter 1@= 0hat is 3eneric Cro&rammin&>!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! @<D Chapter 1A= Concepts!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! @<< Chapter 1?= 8unctors!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! A01 $b%ect&$riented !rogramming............................................................................................................................. ''3 Chapter 16= 'ntroduction to 'nheritance!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! AA? (ore to )*+lore......................................................................................................................................................... ',# Chapter 1D= C++0)!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! AED Chapter 1E= 0here to 3o 8rom /ere!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ?0? A++endices................................................................................................................................................................. #-" ,ppendi) 0= Bovin& from C to C++!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ?11 ,ppendi) 1= Solutions to Cractice Cro#lems!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ?;< Bibliogra+./.............................................................................................................................................................. ##1 Inde*............................................................................................................................................................................. ##3

Table of Contents

!art 0ero
Introduction
Suppose we want to write a function that computes the avera&e of a list of num#ers! Gne implementation is &iven here=
double GetAverage(double arr[], int numElems) { double total = 0.0; for(int h = 0; h numElems; !!h) total != arr[h] " numElems; # return total;

,n alternative implementation is as follows=


tem$late t%$ename &or'ard(terator) double GetAverage(&or'ard(terator begin, &or'ard(terator end) { return a**umulate(begin, end, 0.0) " distan*e(begin, end); #

2on't panic if you don't understand any of this code ( you're not e)pected to at this point ( #ut even without an understandin& of how either of these functions work it's clear that they are implemented differently! ,lthou&h #oth of these functions are valid C++ and accurately compute the avera&ee)perienced C++ pro&rammers will likely prefer the second version to the first #ecause it is safer- more concise- and more versatile! To understand why you would prefer the second version of this function re5uires a solid understandin& of the C++ pro&rammin& lan&ua&e! "ot only must you have a firm &rasp of how all the lan&ua&e features involved in each solution work- #ut you must also understand the #enefits and weaknesses of each of the approaches and ultimately which is a more versatile solution! The purpose of this course is to &et you up to speed on C++'s lan&ua&e features and li#raries to the point where you are capa#le of not only writin& C++ code- #ut also criti5uin& your desi&n decisions and ar&uin& why the cocktail of lan&ua&e features you chose is appropriate for your specific application! This is an am#itious &oal- #ut if you take the time to read throu&h this reader and work out some of the practice pro#lems you should #e in e)cellent C++ shape! 1.o t.is Course is 2or This course is desi&ned to au&ment CS1067HI #y providin& a workin& knowled&e of C++ and its applications! C++ is an industrial1stren&th tool that can #e harnessed to solve a wide array of pro#lemsand #y the time you've completed CS1067HI and CS106 you should #e e5uipped with the skill set necessary to identify solutions to comple) pro#lems- then to precisely and efficiently implement those solutions in C++! This course reader assumes a knowled&e of C++ at the level at which it would #e covered in the first two weeks of CS1067HI! 'n particular- ' assume that you are familiar with the followin&=

1;1 0. 1. 2. 3. 4. . !. $. How to print to the console (i.e. *out and endl) Primitive variable types (int, double, etc.) The string type. enums and stru*ts. 8unctions and function prototypes! Cass1#y1value and pass1#y1reference! "ontrol str#ct#res (if, for, 'hile, do, s'it*h). "%10!&'()speci*ic libraries (genlib.h, sim$io.h, the +,Ts, etc.)

Introduction

'f you are unfamiliar with any of these terms- ' recommend readin& the first chapter of Programming Abstractions in C++ #y Jric Fo#erts and $ulie %elenski- which has an e)cellent treatment of the material! These concepts are fundamental to C++ #ut aren't that particular to the lan&ua&e ( you'll find similar constructs in C- $ava- Cython- and other lan&ua&es ( and so ' won't discuss them at &reat len&th! 'n addition to the lan&ua&e prere5uisites- you should have at least one 5uarter of pro&rammin& e)perience under your #elt KCS106, should #e more than enou&hL! 0e'll #e writin& a lot of code- and the more pro&rammin& savvy you #rin& to this course- the more you'll take out of it! 3ow t.is 4eader is $rgani5ed The course reader is lo&ically divided into si) sections= 0. Introduction= This section motivates and introduces the material and covers information necessary to #e a workin& C++ pro&rammer! 'n particular- it focuses on the history of C++- how to set up a C++ pro*ect for compilation- and how to move away from the genlib.h trainin& wheels we've provided you in CS1067HI! 1. A Better C= C++ supports imperative programming- a style of pro&rammin& in which pro&rams are se5uences of commands e)ecuted in order! 'n this sense- C++ can #e viewed as an e)tension to the C pro&rammin& lan&ua&e which makes day1to1day imperative pro&rammin& more intuitive and easier to use! This section of the course reader introduces some of C++'s most common li#rariesincludin& the standard template li#rary- and shows how to use these li#raries to #uild imperative pro&rams! 'n addition- it e)plores new primitives in the C++ lan&ua&e that ori&inally appeared in the C pro&rammin& lan&ua&e- namely pointers- C strin&s- and the preprocessor! 2. Data Abstraction! 0hat most distin&uishes C++ from its si#lin& C is the idea of data abstractionthat the means #y which a pro&ram e)ecutes can #e separated from the ways in which pro&rammers talk a#out that pro&ram! This section of the course reader e)plores the concept of a#straction- how to model it concretely in C++ usin& the class keyword- and an assortment of lan&ua&e features which can #e used to refine a#stractions more precisely! 3. $b%ect&$riented !rogramming ! G#*ect1oriented pro&rammin& is an entirely different way of thinkin& a#out pro&ram desi&n and can dramatically simplify comple) software systems! The key concepts #ehind o#*ect1orientation are simple- #ut to truly appreciate the power of o#*ect1oriented pro&rammin& you will need to see it in action time and time a&ain! This section of the course reader e)plores ma*or concepts in o#*ect1oriented pro&rammin& and how to realize it in C++ with inheritance and polymorphism! 4. eneric !rogramming! 3eneric pro&rammin& is a style of pro&rammin& which aims to #uild software that can tackle an array of pro#lems far #eyond what it was initially envisioned to perform! 0hile a full treatment of &eneric pro&rammin& is far #eyond the scope of an introductory C++ pro&rammin& class- many of the ideas from &eneric pro&rammin& are accessi#le and can fundamentally chan&e the ways in which you think a#out pro&rammin& in C++! This section

Introduction

1@1

e)plores the main ideas #ehind &eneric pro&rammin& and covers several advanced C++ pro&rammin& techni5ues not typically found in an introductory te)t! . (ore to )*+lore! C++ is an enormous lan&ua&e and there simply isn't enou&h time to cover all of its facets in a sin&le course! To help &uide further e)ploration into C++ pro&rammin&- this course reader ends with a treatment of the future of C++ and a list of references for further readin&! "otice that this course reader focuses on C++'s standard li#raries #efore em#arkin& on a detailed tour of its lan&ua&e features! This may seem #ackwards ( after all- how can you understand li#raries written in a lan&ua&e you have not yet studied> ( #ut from e)perience ' #elieve this is the #est way to learn C++! , comprehensive understandin& of the streams li#rary and ST re5uires a rich understandin& of templatesinheritance- functors- and operator overloadin&- #ut even without knowled&e of these techni5ues it's still possi#le to write nontrivial C++ pro&rams that use these li#raries! 8or e)ample- after a 5uick tour of the streams li#rary and #asic ST containers- we'll see how to write an implementation of the &ame Snake with an ,'1controlled player! ater- once we've e)plored the proper lan&ua&e features- we'll revisit the standard li#raries and see how they're put to&ether! To &ive you a feel for how C++ looks in practice- this course reader contains several e)tended e)amples that demonstrate how to harness the concepts of the previous chapters to solve a particular pro#lem! ' strongly su&&est that you take the time to read over these e)amples and play around with the code! The e)tended e)amples showcase how to use the techni5ues developed in previous chapters- and #y seein& how the different pieces of C++ work to&ether you will #e a much more capa#le coder! 'n addition- ''ve tried to conclude each chapter with a few practice pro#lems! Take a sta# at them ( you'll &et a much more nuanced view of the lan&ua&e if you do! Solutions to some of my favorite pro#lems are &iven in ,ppendi) Gne! J)ercises with solutions are marked with a diamond KL! C++ is a lar&e lan&ua&e and it is impossi#le to cover all of its features in a sin&le course! To help &uide further e)ploration into C++ techni5ues- most chapters contain a 4Bore to J)plore6 section listin& important topics and techni5ues that may prove useful in your future C++ career! 6u++lemental 4eading This course reader is #y no means a complete C++ reference and there are many li#raries and lan&ua&e features that we simply do not have time to cover! /owever- the portions of C++ we do cover are amon& the most1commonly used and you should #e a#le to pick up the remainin& pieces on a need1to1know #asis! 'f you are interested in a more complete reference te)t- 7*arne Stroustrup's The C++ Programming Language, Third Edition is an e)cellent choice! 7e aware that TC++PL is not a tutorial ( it's a reference ( and so you will pro#a#ly want to read the relevant sections from this course reader #efore divin& into it! 'f you're interested in a hy#rid referenceHtutorial- ' would recommend C++ Primer, Fourth Edition #y ippman- a*oie- and Boo! ,s for online resources- the C++ 8,M ite at www!parashift!comHc++1fa51liteH has a &reat discussion of C++'s core lan&ua&e features! cplusplus!com has perhaps the #est covera&e of the C++ standard li#rary on the 'nternet- thou&h its discussion of the lan&ua&e as a whole is fairly limited! $nward and 2orward7

C.a+ter -8 1.at is C99:


_________________________________________________________________________________________________________

C++ is a general purpose programming language with a bias towards systems programming that is a better C supports data abstraction supports ob!ect"oriented programming supports generic programming ( 7*arne Stroustrup- inventor of C++ NStr0<!;O Jvery pro&rammin& lan&ua&e has its own distinct flavor influenced #y its history and desi&n! 7efore seriously studyin& a pro&rammin& lan&ua&e- it's important to learn why the lan&ua&e e)ists and what its o#*ectives are! This chapter covers a 5uick history of C++- alon& with some of its desi&n principles! An Abbre;iated 3istor/ of C99< The story of C++ #e&ins with 7*arne Stroustrup- a 2anish computer scientist workin& toward his Ch2 at Cam#rid&e University! Stroustrup's research focus was distributed systems- software systems split across several computers that communicated over a network to solve a pro#lem! ,t one point durin& his research- Stroustrup came up with a particularly clever idea for a distri#uted system! 7ecause desi&nin& distri#uted systems is an enormously complicated endeavor- Stroustrup decided to test out his idea #y writin& a simulation pro&ram- which is a si&nificantly simpler task! Stroustrup chose to write this simulation pro&ram in a lan&ua&e called Simula- one of the earliest o#*ect1oriented pro&rammin& lan&ua&es! ,s Stroustrup recalled- initially- Simula seemed like the perfect tool for the *o#= 't was a pleasure to write that simulator! The features of Simula were almost ideal for the purpose- and ' was particularly impressed #y the way the concepts of the lan&ua&e helped me think a#out the pro#lems in my application! The class concept allowed me to map my application concepts into the lan&ua&e constructs in a direct way that made my code more reada#le than ' had seen in any other lan&ua&e!!! ' had used Simula #efore!!! #ut was very pleasantly surprised #y the way the mechanisms of the Simula lan&ua&e #ecame increasin&ly helpful as the size of the pro&ram increased! NStr<AO 'n Simula- it was possi#le to model a physical computer usin& a computer ob!ect and a physical network usin& a network ob!ect- and the way that physical computers sent packets over physical networks corresponded to the way computer o#*ects sent and received messa&es from network o#*ects! 7ut while Simula made it easier for Stroustrup to develop the simulator- the resultin& pro&ram was so slow that it failed to produce any meanin&ful results! This was not the fault of Stroustrup's implementation- #ut of the lan&ua&e Simula itself! Simula was #loated and lan&ua&e features Stroustrup didn't use in his pro&ram were cripplin& the simulator's efficiency! 8or e)ample- Stroustrup found that ei&hty percent of his pro&ram time was #ein& spent on &ar#a&e collection despite the fact that the simulation didn't create any &ar#a&e! NStr<AO 'n other words- while Simula had decreased the time re5uired to #uild the simulator- it dramatically increased the time re5uired for the simulator to e)ecute! Stroustrup realized that his Simula1#ased simulator was &oin& nowhere! To continue his researchStroustrup scrapped his Simula implementation and rewrote the pro&ram in a lan&ua&e he knew ran 5uickly and efficiently= 7CC ! 7CC has since &one the way of the dodo- #ut at the time was a widely usedP This section is #ased on information from The #esign and Evolution o$ C++ #y 7*arne Stroustrup!

161

Chapter %& 'hat is C++(

low1level systems pro&rammin& lan&ua&e! Stroustrup later recalled that writin& the simulator in 7CC was 4horri#le!6 NStr<AO ,s a low1level lan&ua&e- 7CC lacked o#*ects and to represent computers and networks Stroustrup had to manually lay out and manipulate the proper #its and #ytes! /owever- 7CC pro&rams were far more efficient than their Simula counterparts- and Stroustrup's updated simulator worked marvelously! Stroustrup's e)periences with the distri#uted systems simulator impressed upon him the need for a more suita#le tool for constructin& lar&e software systems! Stroustrup sou&ht a hy#ridization of the #est features of Simula and 7CC ( a lan&ua&e with #oth hi&h1level constructs and low1level runtime efficiency! ,fter receivin& his Ch2- Stroustrup accepted a position at 7ell a#oratories and #e&an to create such a lan&ua&e! Settlin& on C as a #ase lan&ua&e- Stroustrup incorporated hi&h1level constructs in the style of Simula while still maintainin& C's underlyin& efficiency! ,fter several revisions- C with Classes- as his lan&ua&e was known- accumulated other hi&h1level features and was officially renamed C++! C++ was an overni&ht success and spread rapidly into the pro&rammin& communityQ for many years the num#er of C+ + pro&rammers was dou#lin& every seven months! 7y ;00D- there were over three million C++ pro&rammers worldwide- and despite competition from other lan&ua&es like $ava and Cython the num#er of C++ pro&rammers is still increasin&! NStr0<O 0hat #e&an as Stroustrup's pro*ect at 7ell a#oratories #ecame an 'SG1standardized pro&rammin& lan&ua&e found in a variety of applications! C99 as a =anguage 0hen confronted with a new idea or concept- it's often enli&htenin& to do a 5uick 0ikipedia search to see what others have to say on the su#*ect! 'f you look up C++ this way- one of the first sentences you'll read Kat least- at the time of this writin&L will tell you that C++ is a &eneral1purpose- compiled- statically1typedmultiparadi&m- mid1level pro&rammin& lan&ua&e! 'f you are *ust learnin& C++- this description may seem utterly mystifyin&! /owever- this sentence very aptly captures much of the spirit of C++- and so #efore continuin& our descent into the realm of C++ let's take a few minutes to &o over e)actly what this definition entails! C99 is a eneral&!ur+ose !rogramming =anguage Cro&rammin& lan&ua&es can #e #roadly cate&orized into two classes ( domain1specific pro&rammin& lan&ua&es and &eneral1purpose pro&rammin& lan&ua&es! , lan&ua&e is domain"speci$ic if it is desi&ned to solve a certain class of pro#lems in a particular field! 8or e)ample- the B,T ,7 pro&rammin& lan&ua&e is a domain1specific lan&ua&e desi&ned for numerical and mathematical computin&- and so has concise and ele&ant support for matri) and vector operations! 2omain1specific lan&ua&es tend to #e e)tremely easy to use- particularly #ecause these lan&ua&es let pro&rammers e)press common operations concisely and ele&antly #ecause the lan&ua&e has #een desi&ned with them in mind! ,s an e)ample- in B,T ,7 it is possi#le to solve a linear system of e5uations usin& the simple synta) + = A,b! The e5uivalent C++ or $ava code would #e si&nificantly more comple)! /owever- #ecause domain1specific lan&ua&es are optimized on a particular class of pro#lems- it can #e difficult if not impossi#le to adapt those lan&ua&es into other pro#lem domains! This has to do with the fact that domain1specific lan&ua&es are custom1tailored to the pro#lems they solve- and conse5uently lack the voca#ulary or syntactic richness to e)press structures #eyond their narrow scope! This is #est illustrated #y analo&y ( an e)traordinary mathematician with years of trainin& would pro#a#ly have &reat difficulty holdin& a technical discussion on winemakin& with the world's e)pert oenolo&ist simply #ecause the voca#ularies of mathematics and winemakin& are entirely different! 't mi&ht #e possi#le to e)plain viticulture to the mathematician usin& terms from differential topolo&y or matri) theory- #ut this would clearly #e a mis&uided effort! Contrastin& with domain1specific lan&ua&es are general"purpose lan&ua&es which- as their name su&&estsare desi&ned to tackle all cate&ories of pro#lems- not *ust one particular class! This means that &eneral1 purpose lan&ua&es are more readily adapted to different scenarios and situations- #ut may have a harder time descri#in& some of the fundamental concepts of those domains than a lan&ua&e crafted specifically

Chapter %& 'hat is C++(

1D1

for that purpose! 8or e)ample- an ,merican learnin& 3erman as a second lan&ua&e may #e fluent enou&h in that lan&ua&e to converse with stran&ers and to handle day1to1day life- #ut mi&ht have 5uite an e)perience tryin& to hold a technical conversation with industry specialists! This is not to say- of coursethat the ,merican would not #e a#le to comprehend the ideas that the specialist was puttin& forth- #ut rather that any discussion the two would have would re5uire the specialist to define her terms as the conversation unfolded- rather than takin& their definitions for &ranted at the start! C++ is a &eneral1purpose pro&rammin& lan&ua&e- which means that it is ro#ust enou&h to adapt to handle all sorts of pro#lems without providin& special tools that simplify tasks in any one area! This is a trade1offof course! 7ecause C++ is &eneral1purpose- it will not ma&ically provide you a means for solvin& a particular pro#lemQ you will have to think throu&h a desi&n for your pro&rams in order for them to work correctly! 7ut #ecause C++ is &eneral1purpose- you will #e hard1pressed to find a challen&e for which C++ is a poor choice for the solution! Boreover- #ecause C++ is a &eneral1purpose lan&ua&e- once you have learned the structures and techni5ues of C++- you can apply your knowled&e to any pro#lem domain without havin& to learn new synta) or structures desi&ned for that domain! C99 is a Com+iled =anguage The pro&rams that actually e)ecute on a computer are written in machine lan&ua&e- an e)tremely low1 level and hardware1specific lan&ua&e that encodes individual instructions for the computer's CCU! Bachine lan&ua&es are indeciphera#le even to most workin& pro&rammers #ecause these lan&ua&es are desi&ned to #e read #y computer hardware rather than humans! Conse5uently- pro&rammers write pro&rams in pro&rammin& lan&ua&es- which are desi&ned to #e read #y humans! 'n order to e)ecute a pro&ram written in a pro&rammin& lan&ua&e- that pro&ram must somehow #e converted from its source code representation into e5uivalent machine code for e)ecution! /ow this transformation is performed is not set in stone- and in &eneral there are two ma*or approaches to convertin& source code to machine code! The first of these is to interpret the pro&ram! 'n interpreted languages-a special pro&ram called the interpreter takes in the pro&ram's source code and translates the pro&ram as it is #ein& e)ecuted! 0henever the pro&ram needs to e)ecute a new piece of code- the interpreter reads in the ne)t #it of the source code- converts it into e5uivalent machine code- then e)ecutes the result! This means that if the same interpreted pro&ram is run several times- the interpreter will translate the pro&ram anew every time! The other option is to compile the pro&ram! 'n a compiled language- #efore runnin& the pro&ram- the pro&rammer e)ecutes a special pro&ram called the compiler on the source code which translates the entire pro&ram into machine code! This means that no matter how many times the resultin& pro&ram is run- the compiler is only invoked once! 'n &eneral- interpreted lan&ua&es tend to run more slowly than compiled lan&ua&es #ecause the interpreter must translate the pro&ram as it is #ein& e)ecuted- whereas the translation work has already #een done in the case of compiled lan&ua&es! 7ecause C++ places a premium on efficiency- C++ is a compiled lan&ua&e! 0hile C++ interpreters do e)ist- they are almost e)clusively for research purposes and rarely Kif at allL used in professional settin&s! 0hat does all of this mean for you as a C++ pro&rammer> That is- why does it matter whether C++ is compiled or interpreted> , &reat deal- it turns outQ this will #e ela#orated upon in the ne)t se&ment on static type checkin&! /owever- one way that you will notice immediately is that you will have to compile your pro&rams every time you make a chan&e to the source code that you want to test out! 0hen workin& on very lar&e software pro*ects Kon the order of millions to hundreds of millions of lines of codeL- it is not uncommon for a recompilation to take hours to complete- meanin& that it is difficult to test out lots of minor chan&es to a C++ pro&ram! ,fter all- if every chan&e takes three minutes to test- then the num#er of possi#le chan&es you can make to a pro&ram in hopes of eliminatin& a #u& or e)tendin& functionality can #e &reatly limited! Gn the other hand- thou&h- #ecause C++ is compiled- once you have your resultin& pro&ram it will tend to run much- much faster than pro&rams written in other lan&ua&es! Boreover- you don't need to distri#ute an interpreter for your pro&ram in addition to the source ( #ecause C++ pro&rams compile down directly to the machine code- you can *ust ship an e)ecuta#le file to whoever wants to run your pro&ram and they should #e a#le to run it without any hassle!

1E1 C99 is a 6taticall/&T/+ed =anguage

Chapter %& 'hat is C++(

Gne of the sin&le most important aspects of C++ is that it is a statically1typed lan&ua&e! 'f you want to manipulate data in a C++ pro&ram- you must specify in advance what the type of that data is Kfor e)amplewhether it's an inte&er- a real num#er- Jn&lish te)t- a *et en&ine- etc!L! Boreover- this type is set in stone and cannot chan&e elsewhere in the source code! This means that if you say that an o#*ect is a coffee mu&- you cannot treat it as a stapler someplace else! ,t first this mi&ht seem silly ( o$ course you shouldn't #e a#le to convert a coffee mu& into a stapler or a #all of twine into a *et en&ineQ those are entirely different entitiesR .ou are completely correct a#out this! ,ny pro&ram that tries to treat a coffee mu& as thou&h it is a stapler is #ound to run into trou#le #ecause a coffee mu& isn)t a stapler! The reason that static typin& is important is that these sorts of errors are cau&ht at compile"time instead of at runtime! This means that if you write a pro&ram that tries to make this sort of mistake- the pro&ram won't compile and you won't even have an e)ecuta#le containin& a mistake to run! 'f you write a C++ pro&ram that tries to treat a coffee mu& like a stapler- the compiler will &ive you an error and you will need to fi) the pro#lem #efore you can test out the pro&ram! This is an e)tremely powerful feature of compiled lan&ua&es and will dramatically reduce the num#er of runtime errors that your pro&rams encounter! ,s you will see later in this #ook- this also ena#les you to have the compiler verify that comple) relationships hold in your code and can conclude that if the pro&ram compiles- your code does not contain certain classes of mistakes! C99 is a (ulti&!aradigm =anguage C++ #e&an as a hy#rid of hi&h1 and low1level lan&ua&es #ut has since evolved into a distinctive lan&ua&e with its own idioms and constructs! Bany pro&rammers treat C++ as little more than an o#*ect1oriented C#ut this view o#scures much of the ma&ic of C++! C++ is a multiparadigm pro&rammin& lan&ua&e- meanin& that it supports several different pro&rammin& styles! C++ supports imperative pro&rammin& in the style of C- meanin& that you can treat C++ as an up&raded C! C++ supports ob!ect"oriented pro&rammin&- so you can construct ela#orate class hierarchies that hide comple)ity #ehind simple interfaces! C++ supports generic pro&rammin&- allowin& you to write code reusa#le in a lar&e num#er of conte)ts! 8inally- C++ supports a limited form of higher"order pro&rammin&- allowin& you to write functions that construct and manipulate other functions at runtime! C++ #ein& a multiparadi&m lan&ua&e is #oth a #lessin& and a curse! 't is a #lessin& in that C++ will let you write code in the style that you feel is most appropriate for a &iven pro#lem- rather than ri&idly lockin& you into a particular framework! 't is also a #lessin& in that you can mi) and match styles to create pro&rams that are precisely suited for the task at hand! 't is a curse- however- in that multiparadi&m lan&ua&es are necessarily more comple) than sin&le1paradi&m lan&ua&es and conse5uently C++ is more difficult to pick up than other lan&ua&es! Boreover- the interplay amon& all of these paradi&ms is comple)and you will need to learn the su#tle #ut important interactions that occur at the interface #etween these paradi&ms! This #ook is or&anized so that it covers a mi)ture of all of the aforementioned paradi&ms one after another- and ideally you will #e comforta#le workin& in each #y the time you've finished readin&! C99 is a (id&=e;el =anguage Computer pro&rams ultimately must e)ecute on computers! ,lthou&h computers are capa#le of e)ecutin& pro&rams which perform comple) a#stract reasonin&- the computers themselves understand only the small set of commands necessary to manipulate #its and #ytes and to perform simple arithmetic! ow1 level lan&ua&es are lan&ua&es like C and assem#ly lan&ua&e that provide minimal structure over the actual machine and e)pose many details a#out the inner workin&s of the computer! To contrast- hi&h1level lan&ua&es are lan&ua&es that a#stract away from the particulars of the machine and let you write

Chapter %& 'hat is C++(

1<1

pro&rams independently of the computer's idiosyncrasies! ,s mentioned earlier- low1level lan&ua&es make it hard to represent comple) pro&ram structure- while hi&h1level lan&ua&es often are too a#stract to operate efficiently on a computer! C++ is a rare lan&ua&e in that it com#ines the low1level efficiency and machine access of C with hi&h1level constructs like those found in $ava! This means that it is possi#le to write C++ pro&rams with the stren&ths of #oth approaches! 't is not uncommon to find C++ pro&rams that model comple) systems usin& o#*ect1 oriented techni5ues Khi&h levelL while takin& advanta&e of specific hardware to accelerate that simulation Klow1levelL! Gne way to think a#out the power afforded #y C++ is to reco&nize that C++ is a lan&ua&e that provides a set of a#stractions that let you intuitively desi&n lar&e software systems- #ut which lets you #reak those a#stractions when the need to optimize #ecomes important! 0e will see some ways to accomplish this later in this #ook! Design !.iloso+./ C++ is a comparatively old lan&ua&eQ its first release was in 1<E?! Since then numerous other pro&rammin& lan&ua&es have sprun& up ( $ava- Cython- CS- and $avascript- to name a few! /ow e)actly has C++ survived so lon& when others have failed> C++ may #e useful and versatile- #ut so were 7CC and Simula- neither of which are in widespread use today! Gne of the main reasons that C++ is still in use Kand evolvin&L today has #een its core &uidin& principles! Stroustrup has maintained an active interest in C++ since its inception and has steadfastly adhered to a particular desi&n philosophy! /ere is a samplin& of the desi&n points- as articulated in Stroustrup's The #esign and Evolution o$ C++! C99>s e;olution must be dri;en b/ real +roblems 0hen e)istin& pro&rammin& styles prove insufficient for modern challen&es- C++ adapts! 8or e)ample- the introduction of e)ception handlin& provided a much1needed system for error recovery- and a#stract classes allowed pro&rammers to define interfaces more naturally! Don>t tr/ to force +eo+le! C++ supports multiple pro&rammin& styles! .ou can write code similar to that found in pure C- desi&n class hierarchies as you would in $ava- or develop software somewhere in #etween the two! C++ respects and trusts you as a pro&rammer- allowin& you to write the style of code you find most suita#le to the task at hand rather than ri&idly lockin& you into a sin&le pattern! Alwa/s +ro;ide a transition +at. C++ is desi&ned such that the pro&rammin& principles and techni5ues developed at any point in its history are still applica#le! 0ith few e)ceptions- C++ code written ten or twenty years a&o should still compile and run on modern C++ compilers! BoreoverC++ is desi&ned to #e mostly #ackwards1compati#le with C- meanin& that veteran C coders can 5uickly &et up to speed with C++!

T.e oal of C99 There is one 5uote from Stroustrup KNStr<AOL ' #elieve #est sums up C++= C++ ma*es programming more enjoyable $or serious programmers 0hat e)actly does this mean> et's #e&in with what constitutes a serious programmer! Fi&idly definin& 4serious pro&rammer6 is difficult- so instead ''ll list some of the pro&rams and pro*ects written in C++ and leave it as an e)ercise to the reader to infer a proper definition! 8or e)ample- you'll find C++ in=

1 10 1

Chapter %& 'hat is C++( (o5illa 2irefo*! The core infrastructure underlyin& all Bozilla pro*ects is written predominantly in C++! 0hile much of the code for 8irefo) is written in $avascript and IU - these lan&ua&es are e)ecuted #y interpreters written in C++! The 0e#Kit layout en&ine used #y Safari and 3oo&le Chrome is also written in C++! ,lthou&h it's closed1source- ' suspect that 'nternet J)plorer is also written in C++! 'f you're #rowsin& the we#- you're seein& C++ in action!

?a;a 3ot6+ot! The widespread success of $ava is in part due to +ot,pot- Sun's implementation of the $ava Tirtual Bachine! /otSpot supports *ust1in1time compilation and optimization and is a #eautifully en&ineered piece of software! 't's also written in C++! The ne)t time that someone en&a&es you in a de#ate a#out the relative merits of C++ and $ava- you can mention that if not for a well1architected C++ pro&ram $ava would not #e a competitive lan&ua&e!

@A6A A ?!=. The rovers currently e)plorin& the surface of Bars have their autonomous drivin& systems written in C++! C++ is on -ars.

C++ ma*es programming more enjoyable $or serious programmers! "ot only does C++ power all of the a#ove applications- it powers them in style! .ou can pro&ram with hi&h1level constructs yet en*oy the runtime efficiency of a low1level lan&ua&e like C! .ou can choose the pro&rammin& style that's ri&ht for you and work in a lan&ua&e that trusts and respects your e)pertise! .ou can write code once that you will reuse time and time a&ain! This is what C++ is all a#out- and the purpose of this #ook is to &et you up to speed on the mechanics- style- and *ust plain e)citement of C++! 0ith that said- let's dive into C++! Gur *ourney #e&insR

C.a+ter 18 etting 6tarted


_________________________________________________________________________________________________________

Jvery *ourney #e&ins with a sin&le step- and in ours it's &ettin& to the point where you can compile- linkrun- and de#u& C++ pro&rams! This depends on what operatin& system you have- so in this section we'll see how to &et a C++ pro*ect up and runnin& under 0indows- Bac GS I- and inu)! Com+iling C99 !rograms under 1indows This section assumes that you are usin& Bicrosoft Tisual Studio ;00? KTS;00?L! 'f you are a current CS1067HI student- you can follow the directions on the course we#site to o#tain a copy! Gtherwise- #e prepared to shell out some cash to &et your own copy- thou&h it is definitely a worthwhile investment! P ,lternatively- you can download Tisual C++ ;00E J)press Jdition- a free version of Bicrosoft's development environment sportin& a fully1functional C++ compiler! The e)press edition of Tisual C++ lacks support for advanced 0indows development- #ut is otherwise a perfectly fine C++ compiler! .ou can &et Tisual C++ ;00E J)press Jdition from http=HHwww!microsoft!comHe)pressHvcH! 0ith only a few minor chan&es- the directions for usin& TS;00? should also apply to Tisual C++ ;00E J)press Jdition- so this section will only cover TS;00?! TS;00? or&anizes C++ code into 4pro*ects-6 collections of source and header files that will #e #uilt into a pro&ram! The first step in creatin& a C++ pro&ram is to &et an empty C++ pro*ect up and runnin&- then to populate it with the necessary files! To #e&in- open TS;00? and from the 2ile menu choose @ew B !ro%ect...! .ou should see a window that looks like this=

P ' first #e&an pro&rammin& in C++ in ;001 usin& Bicrosoft Tisual C++ 6!0- which cost rou&hly ei&hty dollars! ' recently K;00EL switched to Tisual Studio ;00?! This means that the compiler cost *ust over ten dollars a year! Considerin& the sheer num#er of hours ' have spent pro&rammin&- this was pro#a#ly the #est investment ' have made!

1 1; 1

Chapter /& 0etting ,tarted

,s you can see- TS;00? has template support for all sorts of different pro*ects- most of which are for Bicrosoft1specific applications such as dynamic1link li#raries K2 sL or ,ctiveI controls! 0e're not particularly interested in most of these choices ( we *ust want a simple C++ pro&ramR To create one- find and choose 1in32 Console A++lication! 3ive your pro*ect an appropriate name- then click $C! .ou should now see a window that looks like this- which will ask you to confi&ure pro*ect settin&s=

"ote that the window title will have the name of the pro*ect you entered in the previous step in its titleQ 4.et ,nother C++ Cro&ram6 is a placeholder! ,t this point- you do not want to click 2inis.! 'nstead- hit @e*t B and you'll #e presented with the followin& screen=

Chapter /& 0etting ,tarted

1 1@ 1

Keep all of the default settin&s listed here- #ut make sure that you check the #o) marked )m+t/ !ro%ect! Gtherwise TS;00? will &ive you a pro*ect with all sorts of Bicrosoft1specific features #uilt into it! Gnce you've checked that #o)- click 2inis. and you'll have a fully functional Kal#eit emptyL C++ pro*ect! "ow- it's time to create and add some source files to this pro*ect so that you can enter C++ code! To do this&o to !ro%ect B Add @ew Item... Kor press CTF +S/'8T+,L! .ou'll #e presented with the followin& dialo& #o)=

1 1A 1

Chapter /& 0etting ,tarted

Choose C99 2ile D.c++E and enter a name for it inside the "ame field! TS;00? automatically appends !cpp to the end of the filename- so don't worry a#out manually enterin& the e)tension! Gnce you're ready- click Add and you should have your source file ready to &o! ,ny C++ code you enter in here will #e considered #y the compiler and #uilt into your final application! Gnce you've written the source code- you can compile and run your pro&rams #y pressin& 2#- choosin& DebugB 6tart Debugging- or clickin& the &reen 4play6 icon! 7y default TS;00? will close the console window after your pro&ram finishes runnin&- and if you want the window to persist after the pro&ram finishes e)ecutin& you can run the pro&ram without de#u&&in& #y pressin& CT4=92# or choosin& Debug B 6tart 1it.out Debugging ! .ou should #e all set to &oR Com+iling C99 !rograms in (ac $6 F 'f you're developin& C++ pro&rams on Bac GS I- your #est option is to use ,pple's Icode development environment! .ou can download Icode free of char&e from the ,pple 2eveloper Connection we#site at http=HHdeveloper!apple!comH! Gnce you've downloaded and installed Icode- it's reasona#ly strai&htforward to create a new C++ pro*ect! Gpen Icode! The first time that you run the pro&ram you'll &et a nice welcome screen- which you're free to peruse #ut which you can safely dismiss! To create a C++ pro*ect- choose 2ile B @ew !ro%ect...! .ou'll #e presented with a screen that looks like this=

Chapter /& 0etting ,tarted

1 1? 1

There are a lot of options here- most of which are ,pple1specific or use lan&ua&es other than C++ Ksuch as $ava or G#*ective1CL! 'n the panel on the left side of the screen- choose Command =ine Gtilit/ and you will see the followin& options=

Select C99 Tool and click the C.oose... #utton! .ou'll #e prompted for a pro*ect name and directoryQ feel free to choose whatever name and location you'd like! 'n this e)ample ''ve used the name 4.et ,nother C+

1 16 1

Chapter /& 0etting ,tarted

+ Cro*ect-6 thou&h ' su&&est you pick a more descriptive name! Gnce you've made your selection- you'll see the pro*ect window- which looks like this=

"otice that your pro*ect comes prepacka&ed with a file called main!cpp! This is a C++ source file that will #e compiled and linked into the final pro&ram! 7y default- it contains a skeleton implementation of the /ello- 0orldR pro&ram- as shown here=

Chapter /& 0etting ,tarted 8eel free to delete any of the code you see here and rewrite it as you see fit!

1 1D 1

7ecause the pro&ram we've *ust created is a command1line utility- you will need to pull up the console window to see the output from your pro&ram! .ou can do this #y choosin& 4un B Console or #y pressin& UF! 'nitially the console will #e empty- as shown here=

Gnce you've run your pro&ram- the output will #e displayed here in the console! .ou can run the pro&ram #y clickin& the Build and o #utton Kthe hammer ne)t to a &reen circle containin& an arrowL! That's itR .ou now have a workin& C++ pro*ect! 'f you're interested in compilin& pro&rams from the Bac GS I terminal- you mi&ht find the followin& section on inu) development useful! Com+iling C99 !rograms under =inu* 8or those of you usin& a inu)1#ased operatin& system- you're in luck ( inu) is e)tremely developer1 friendly and all of the tools you'll need are at your disposal from the command1line! Unlike the 0indows or Bac environments- when compilin& code in inu) you won't need to set up a development environment usin& Tisual Studio or Icode! 'nstead- you'll *ust set up a directory where you'll put and edit your C++ files- then will directly invoke the 3"U C++ Compiler K g!!L from the command1line! 'f you're usin& inu) ''ll assume that you're already familiar with simple commands like mkdir and chdir and that you know how to edit and save a te)t document! 0hen writin& C++ source code- you'll pro#a#ly want to save header files with the !h e)tension and C++ files with the !cc- !cpp- !C- or !c++ e)tension! The !cc e)tension seems to #e in vo&ue these days- thou&h !cpp is also 5uite popular! To compile your source code- you can e)ecute g!! from the command line #y typin& g!! and then a list of the files you want to compile! 8or e)ample- to compile m%file.** and m%otherfile.**- you'd type
g!! m%file.** m%otherfile.**

1 1E 1

Chapter /& 0etting ,tarted

7y default- this produces a file named a.out- which you can e)ecute #y enterin& ."a.out! 'f you want to chan&e the name of the pro&ram to somethin& else- you can use g!!'s -o switch- which produces an output file of a different name! 8or e)ample- to create an e)ecuta#le called mypro&ram from the file myfile!cc- you could write
g!! m%file.** -o myprogram g!! has a whole host of other switches Ksuch as -* to compile #ut not link a fileL- so #e sure to consult the man pa&es for more info!

't can &et tedious writin& out the commands to compile every sin&le file in a pro*ect to form a finished e)ecuta#le- so most inu) developers use ma*e$iles- scripts which allow you to compile an entire pro*ect #y typin& the make command! , full tour of makefiles is far #eyond the scope of an introductory C++ te)t#ut fortunately there are many &ood online tutorials on how to construct a makefile! The full manual for make is availa#le online at http=HHwww!&nu!or&HsoftwareHmakeHmanualHmake!html! $t.er De;elo+ment Tools 'f you are interested in usin& other development environments than the ones listed a#ove- you're in luck! There are dozens of '2Js availa#le that work on a wide ran&e of platforms! /ere's a small samplin&= @etBeans= The "et7eans '2J supports C++ pro&rammin& and is hi&hly customiza#le! 't also is completely cross1platform compati#le- so you can use it on 0indows- Bac GS I- and inu)! (in 1= Bin30 is a port of common 3"U tools to Bicrosoft 0indows- so you can use tools like g!! without runnin& inu)! Bany lar&e software pro*ects use Bin30 as part of their #uild environment- so you mi&ht want to e)plore what it offers you! )cli+se= This popular $ava '2J can #e confi&ured to run as a C++ compiler with a #it of additional effort! 'f you're usin& 0indows you mi&ht need to install some additional software to &et this '2J workin&- #ut otherwise it should #e reasona#ly strai&htforward to confi&ure! 6un 6tudio= 'f you're a inu) user and command1line hackin& isn't your cup of tea- you mi&ht want to consider installin& Sun Studio- Sun Bicrosystem's C++ development environment- which has a wonderful 3U' and solid de#u&&in& support! Ht Creator= This inu)1#ased '2J is desi&ned to #uild C++ pro&rams usin& the open1source Mt li#raries- #ut is also an e)cellent &eneral1purpose C++ '2J! 't is a ma*or step a#ove what the terminal and your favorite te)t editor have to offer- and ' hi&hly recommend that you check this pro&ram out if you're a inu) *unkie!

C.a+ter 28 C99 1it.out genlib.h


_________________________________________________________________________________________________________

0hen you arrived at your first CS1067HI lecture- you pro#a#ly learned to write a simple 4/ello- 0orld6 pro&ram like the one shown #elow=
.in*lude /genlib.h/ .in*lude iostream) int main() { *out /0ello, 'orld1/ return 0; # endl;

0hether or not you have previous e)perience with C++- you pro#a#ly realized that the first line means that the source code references an e)ternal file called genlib.h! 8or the purposes of CS1067HI- this is entirely accepta#le Kin fact- it's re5uiredRL- #ut once you mi&rate from the educational settin& to professional code you will run into trou#le #ecause genlib.h is not a standard header fileQ it's included in the CS1067HI li#raries to simplify certain lan&ua&e features so you can focus on writin& code- rather than appeasin& the compiler! 'n CS106 - none of our pro&rams will use genlib.h- sim$io.h- or any of the other CS1067HI li#rary files! 2on't worry- thou&h- #ecause none of the functions e)ported #y these files are 4ma&ical!6 'n fact- in the ne)t few chapters you will learn how to rewrite or supersede the functions and classes e)ported #y the CS1067HI li#raries!P 'f you have the time- ' encoura&e you to actually open up the &enli#!h file and peek around at its contents! To write 4/ello- 0orld6 without genlib.h- you'll need to add another line to your pro&ram! The 4pure6 C+ + version of 4/ello- 0orld6 thus looks somethin& like this=
.in*lude iostream) using names$a*e std; int main() { *out /0ello, 2orld1/ return 0; # endl;

0e've replaced the header file genlib.h with the cryptic statement 4 using names$a*e std;6 7efore e)plainin& e)actly what this statement does- we need to take a 5uick diversion to lessons learned from development history! Suppose you're workin& at a company that produces two types of software= &raphics desi&n pro&rams and online &unfi&hter duels Kadmittedly- this com#ination is pretty unlikely- #ut humor me for a whileL! Jach pro*ect has its own source code files complete with a set of helper functions and classes! /ere are some sample header files from each pro*ect- with most of the commentin& removed=

P The e)ceptions are the &raphics and sound li#raries! C++ does not have natural lan&ua&e support for multimediaand althou&h many such li#raries e)ist- we won't cover them in this te)t!

1 ;0 1 0raphics2tility h&
"3 &ile4 gra$hi*sutilit%.h 3 Gra$hi*s utilit% fun*tions. 3" "3 5lear6*ene4 5lears the *urrent s*ene. 3" void 5lear6*ene(); "3 Add7ine4 Adds a line to the *urrent s*ene. 3" void Add7ine(int +0, int %0, int +8, int %8); "3 9ra'4 9ra's the *urrent s*ene. 3" void 9ra'();

Chapter 1& C++ 'ithout genlib h

0un$ighter2tility h&
"3 &ile4 gunfighterutilit%.h 3 Gunfighter utilit% fun*tions. 3" "3 :ar*h;en<a*es4 :ar*hes ten $a*es, animating ea*h ste$. 3" void :ar*h;en<a*es(<la%er=b>e*t ?to:ove); "3 &a*e&oe4 ;urns to fa*e the o$$onent. 3" void &a*e&oe(); "3 9ra'4 @nholsters and aims the $istol. 3" void 9ra'();

Suppose the &unfi&hter team is implementin& :ar*h;en<a*es and needs to animate the &unfi&hters walkin& away from one another! Fealizin& that the &raphics team has already implemented an entire li#rary &eared toward this- the &unfi&hter pro&rammers import &raphicsutility!h into their pro*ect- write code usin& the &raphics functions- and try to compile! /owever- when they try to test their code- the linker reports errors to the effect of 4error4 fun*tion Avoid 9ra'()A alread% defined.6 The pro#lem is that the &raphics and &unfi&hter modules each contain functions named 9ra'() with the same si&nature and the compiler can't distin&uish #etween them! 't's impractical for either team to rename their 9ra' function- #oth #ecause the other pro&rammin& teams e)pect them to provide functions named 9ra' and #ecause their code is already filled with calls to 9ra'! 8ortunately- there's an ele&ant resolution to this pro#lem! Jnter the C++ names$a*e keyword! , namespace adds another layer of namin& onto your functions and varia#les! 8or e)ample- if all of the &unfi&hter code was in the namespace 4Gunfighter-6 the function 9ra' would have the full name Gunfighter449ra'! Similarly- if the &raphics pro&rammers put their code inside namespace 4 Gra$hi*s-6 they would reference the function 9ra' as Gra$hi*s449ra'! 'f this is the case- there is no lon&er any am#i&uity #etween the two functions- and the &unfi&hter development team can compile their code! 7ut there's still one pro#lem ( other pro&rammin& teams e)pect to find functions named 5lear6*ene and &a*e&oe- not Gra$hi*s445lear6*ene and Gunfighter44&a*e&oe! 8ortunately- C++ allows what's known as a using declaration that lets you i&nore fully 5ualified names from a namespace and instead use the shorter names! 7ack to the /ello- 0orld e)ample- reprinted here=

Chapter 1& C++ 'ithout genlib h


.in*lude iostream) using names$a*e std; int main() { *out /0ello, 2orld1/ return 0; # endl;

1 ;1 1

The statement 4using names$a*e std;6 followin& the .in*lude directive tells the compiler that all of the functions and classes in the namespace std can #e used without their fully15ualified names! This 4 std6 namespace is the C++ standard namespace that includes all the li#rary functions and classes of the standard li#rary! 8or e)ample- cout is truly named std==cout- and without the usin& declaration importin& the std namespace- /ello- 0orld would look somethin& like this=
.in*lude iostream) /0ello, 2orld1/ std44endl;

int main() { std44*out return 0; #

0hile some pro&rammers prefer to use the fully15ualified names when usin& standard li#rary components- repeatedly writin& std44 can #e a hassle! To eliminate this pro#lem- in genlib.h- we included the using declaration for you! 7ut now that we've taken the trainin& wheels off and genlib.h is no more- you'll have to remem#er to include it yourselfR There's one more important part of genlib.h- the string type! Unlike other pro&rammin& lan&ua&esC++ lacks a primitive strin& type! P Sure- there's the class string- #ut unlike int or double it's not a #uilt1 in type and must #e included with a .in*lude directive! Specifically- you'll need to write .in*lude string) at the top of any pro&ram that wants to use C++1style strin&s! ,nd don't for&et the using declaration- or you'll need to write std44string every time you want to use C++ strin&sR

P Technically speakin& there are primitive strin&s in C++- #ut they aren't o#*ects! See the chapter on C strin&s for more information!

!art $ne
A Better C

C.a+ter 38 6treams
_________________________________________________________________________________________________________

't's time to #e&in our serious foray into the ma&ical world of C++ pro&rammin&! 'n this first chapter- we'll e)plore C++'s streams library- a collection of functions that allow you to read and write formatted data from a variety of sources! The streams li#rary allows your pro&ram to print te)t to the user and read #ack responses! 't also lets you load persistent data from e)ternal files and to save custom information on1disk! ,s you continue your e)ploration of C++- you will use the contents of this chapter time and time a&ainwhether for simple error1reportin& or more comple) data mana&ement! 6treams8 An $;er;iew 'n the physical world- all interestin& devices have some way of interactin& with their environment! Take a common alcohol thermometer- for e)ample! The thermometer has a li5uid1filled #ul# that is warmed up #y the environment and a &raduated meter which allows the user to read off the temperature near the #ul#! Gr consider a car- which has an accelerator- #rake- &ear#o)- and steerin& wheel to control the direction and speed of the vehicle and a dash#oard which reports the current state of the automo#ile! C+ +'s streams li#rary is the primary means #y which a C++ pro&ram can interact with its environmentnamely the user and the file system! The #asic unit of communication #etween a pro&ram and its environment is a stream! , stream is a channel #etween a source and a destination which allows the source to push formatted data to the destination! The type of the source and the sink varies from stream to stream! 'n some streams the source is the pro&ram itself and the destination is a file on disk- and the stream can #e used to write persistent data to the user's hard drive! 'n others- the source is the key#oard and the destination is the pro&ram- and the stream can #e used to read user input from the physical world into the computer! The use of the term 4stream6 in the conte)t of the streams li#rary is similar to the use of 4stream6 in the conte)t of 4streamin& video!6 0hen a data provider Kfor e)ample- .ouTu#eL streams video over the 'nternet- the video is not sent all at once! 'nstead- the pro&ram receivin& the video continuously 5ueries the server for more and more information- and the video is sent in fi)ed1size chunks and reassem#led #y the video player! 0hen usin& the streams li#rary to read or write data- you do not need to read or write all of the data at once! 't's perfectly le&al Kand 5uite commonL to read the data one piece at a time! 8or e)ample- if you want to read data from a file- instead of loadin& all of the file contents at once- you can read the file line1#y1line- or character1#y1character- or usin& some hy#rid approach! This &ives you &reat fle)i#ility- since you can read different pieces of the file in different ways to &et the data in a format appropriate to your application! To &ive you a #etter sense of how streams work in practice- let's consider an actual stream- *out! *out Kfor character outputL is a stream connected to the console- a te)t window that displays plain te)t data! ,ny information pushed across *out displays in the console- and so you can think of *out as a way of displayin& data to the user! 8or e)ample- here's a simple pro&ram which displays a messa&e to the user and then 5uits=
.in*lude iostream) using names$a*e std; int main() { *out /(Am sorr% 9ave, (Am afraid ( *anAt do that./ return 0; # endl;

1 ;6 1

Chapter 3& ,treams

There's a lot of code here- so let's take a few minutes to dissect it! The first line of the pro&ram- .in*lude iostream)- instructs the C++ compiler to import the *out stream into the pro&ram! The line using names$a*e std is covered in the previous chapter and makes the *out stream availa#le! 'nside of mainwe have the followin& line of code=
*out /(Am sorr% 9ave, (Am afraid ( *anAt do that./ endl;

The special operator is called the stream insertion operator and is a C++ operator that is used to push data into a stream o#*ect! /ere- we push the te)t strin& (Am sorr% 9ave, (Am afraid ( *anAt do that into the *out stream! This causes the this te)t to display on1screen! ,fterwards- we push the special o#*ect endl into the stream! endl stands for 4end line6 and prints a newline character to the *out stream! This means that the ne)t time we push te)t into *out- the te)t will display on the ne)t line- rather than directly after the te)t strin& we *ust printed! 0e'll discuss endl in more detail later in this chapter! Streams are very versatile and you can write data of multiple types to stream o#*ects! 'n fact- you can push data of any primitive type into a stream! 8or e)ample- here's a pro&ram showin& off the sorts of data that can move across a stream=
.in*lude iostream) using names$a*e std; int main() { *out /6treams *an taBe in te+t./ endl; *out 8CD endl; "" 6treams *an taBe in integers. *out E.D8FEF endl; "" 6treams *an taBe in real numbers. *out /0ere is te+t follo'ed b% a number4 / C8G8H endl; return 0; #

Funnin& this pro&ram will produce the followin& output=


6treams *an taBe in te+t. 8CD E.D8FEF 0ere is te+t follo'ed b% a number4 C8G8H

'n the first line of this pro&ram- we sent a te)t strin& to the console! 'n the second and third- we sent an inte&er and a natural num#er- respectively! The last line is perhaps the most interestin&! 'n it- we push #oth a strin& and an inte&er to the console #y chainin& to&ether the stream insertion operator! The desi&ners of the streams li#rary were fairly clever- and so it's perfectly le&al to chain to&ether as many stream insertions as you'd like! To &ive you a #etter feel for why each of the stream operations in the a#ove pro&ram end #y pushin& endl into the stream- let's consider what would happen if this weren't the case! /ere's a revised version of the a#ove pro&ram will all instances of endl removed=

Chapter 3& ,treams


.in*lude iostream) using names$a*e std; int main() { *out /6treams *an taBe in te+t./; *out 8CD; *out E.D8FEF; *out /0ere is te+t follo'ed b% a number4 / return 0; #

1 ;D 1

C8G8H;

This produces the followin& output=


6treams *an taBe in te+t.8CDE.D8FEF0ere is te+t follo'ed b% a number4 C8G8H

"otice that all of this te)t runs to&ether! C++ will not 4automatically6 insert newlines into any te)t you write- and when outputtin& data to the console you will need to manually insert line #reaks! ,s a &eneral rule- most of the time that you use *out to push data to the console- you will need to append endl to ensure the output doesn't all run to&ether! ,ll of the stream e)amples we have seen so far have revolved around *out and pushin& data from the pro&ram to the console! To #uild a truly interactive pro&ram- however- we'll need to &et input from the user! 'n CS1067HI- we provide the sim$io.h header file- which e)ports the input functions Get7ineGet(nteger- GetIeal- and Get7ong! Thou&h useful- these functions are not part of the C++ standard li#rary and will not #e availa#le outside of CS1067HI! 2on't worry- thou&h- #ecause #y the end of this chapter we'll see how to implement them usin& only standard C++! The streams li#rary e)ports another stream o#*ect called *in Kcharacter inputL which lets you read values directly from the user! To read a value from *in- you use the stream e4traction operator ))! Syntacticallythe stream e)traction operator mirrors the stream insertion operator! 8or e)ample- here's a code snippet to prompt the user for an inte&er!
*out /<lease enter an integer4 /;

int m%(nteger; *in )) m%(nteger; "" Jalue stored in m%(nteger

0hen the pro&ram encounters the hi&hli&hted line- it will pause and wait for the user to type in a num#er and hit enter! Crovided that the user actually enters an inte&er- its value will #e stored inside the m%(nteger varia#le! 0hat happens if the user doesn)t enter an inte&er is a #it more complicated- and we'll return to this later in the chapter! .ou can also read multiple values from *in #y chainin& to&ether the stream e)traction operator in the same way that you can write multiple values to *out #y chainin& the stream insertion operator=
int m%(nteger; string m%6tring; *in )) m%(nteger )) m%6tring; "" Iead an integer and string from *in

This will pause until the user enters an inte&er- hits enter- then enters a strin&- then hits enter once more! These values will #e stored in m%(nteger and m%6tring- respectively! "ote that when usin& *in- you should not read into endl the way that you write endl when usin& *out! /ence the followin& code is ille&al=

1 ;E 1
int m%(nteger; *in )) m%(nteger )) endl; "" Error4 5annot read into endl.

Chapter 3& ,treams

'ntuitively- this makes sense #ecause endl means 4print a newline!6 Feadin& a value into endl is therefore a nonsensical operation! 'n practice- it is not a &ood idea to read values directly from *in! Unlike Get(nteger and the like- *in does not perform any safety checkin& of user input and if the user does not enter valid data- *in will #e&in #ehavin& unusually! ater in this chapter- we will see how the Get(nteger function is implemented and you will #e a#le to use the function in your own pro&rams! 'n the meantime- thou&h- feel free to use *in#ut make sure that you always type in input correctlyR 4eading and 1riting 2iles So far- we have seen two e)amples of streams ( *out- which sends data to the console- and *in- which reads data from the key#oard! 'n this ne)t section we'll see two new kinds of streams ( ifstreams and ofstreams ( which can #e used to read or write files on disk! This will allow your pro&ram to save data indefinitely- or to read in confi&uration data from an e)ternal source! C++ provides a header file called fstream) Kfile streamL that e)ports the ifstream and ofstream types- streams that perform file 'HG! The namin& convention is unfortunate ( ifstream stands for input file stream Knot 4somethin& that mi&ht #e a stream6L and ofstream for output file stream! There is also a &eneric fstream class which can do #oth input and output- #ut we will not cover it in this chapter! Unlike *in and *out- which are concrete stream o#*ects- ifstream and ofstream are types! To read or write from a file- you will create an o#*ect of type ifstream or ofstream- much in the same way that you would create an o#*ect of type string to store te)t data or a varia#le of type double to hold a real num#er! Gnce you have created the file stream o#*ect- you can read or write to it usin& the stream insertion and e)traction operators *ust as you would *in or *out! To create an ifstream that reads from a file- you can use this synta)=
ifstream m%6tream(/m%&ile.t+t/);

This creates a new stream o#*ect named m%6tream which reads from the file m%&ile.t+t- provided of course that the file e)ists! 0e can then read data from m%6tream *ust as we would from *in- as shown here=
ifstream m%6tream(/m%&ile.t+t/); int m%(nteger; m%6tream )) m%(nteger; "" Iead an integer from m%&ile.t+t

"otice that we wrote m%6tream )) m%(nteger rather than ifstream )) m%(nteger! 0hen readin& data from a file stream- you must read from the stream varia#le rather than the ifstream type! 'f you read from ifstream instead of your stream varia#le- the pro&ram will not compile and will &ive you a fairly cryptic error messa&e! .ou can also open a file #y usin& the ifstream's o$en mem#er function- as shown here=
ifstream m%6tream; "" Kote4 did not s$e*if% the file m%6tream.o$en(/m%&ile.t+t/); "" Ko' reading from m%&ile.t+t

0hen openin& a file usin& an ifstream- there is a chance that the specified file can't #e opened! The filename mi&ht not specify an actual file- you mi&ht not have permission to read the file- or perhaps the file

Chapter 3& ,treams

1 ;< 1

is locked! 'f you try readin& data from an ifstream that is not associated with an open file- the read will fail and you will not &et #ack meanin&ful data! ,fter tryin& to open a file- you should check if the stream is valid #y usin& the .isLo$en() mem#er function! 8or e)ample- here's code to open a file and report an error to the user if a pro#lem occurred=
ifstream in$ut(/m%file.t+t/); if(1in$ut.isLo$en()) *err /5ouldnAt o$en the file m%file.t+t/

endl;

"otice that we report the error to the *err stream! *err- like *out- is an output stream- #ut unlike *out*err is desi&ned for error reportin& and is sometimes handled differently #y the operatin& system! The output counterpart to ifstream is ofstream! ,s with ifstream- you specify which file to write to either #y usin& the .o$en() mem#er function or #y specifyin& the file when you create the ofstream- as shown #elow=
ofstream m%6tream(/m%&ile.t+t/); "" 2rite to m%&ile.t+t

, word of warnin&= if you try writin& to a none)istent file with an ofstream- the ofstream will create the file for you! /owever- if you open a file that already e)ists- the ofstream will overwrite all of the contents of the file! 7e careful not to write to important files without first #ackin& them upR The streams li#rary is one of the older li#raries in C++ and the o$en functions on the ifstream and ofstream classes predate the string type! 'f you have the name of a file stored in a C++ string- you will need to convert the string into a C1style strin& Kcovered in the second half of this #ookL #efore passin& it as a parameter to o$en! This can #e done usin& the .*Lstr() mem#er function of the string class- as shown here=
ifstream in$ut(m%6tring.*Lstr()); "" =$en the filename stored in m%6tring

0hen a file stream o#*ect &oes out of scope- C++ will automatically close the file for you so that other processes can read and write the file! 'f you want to close the file prematurely- you can use the .*lose() mem#er function! ,fter callin& *lose- readin& or writin& to or from the file stream will fail! ,s mentioned a#ove in the section on *in- when readin& from or writin& to files you will need to do e)tensive error checkin& to ensure that the operations succeed! ,&ain- we'll see how to do this later! 6tream (ani+ulators Consider the followin& code that prints data to *out= cout VV WThis is a strin&RW VV endlQ 0hat e)actly is endl> 't's an e)ample of a stream manipulator- an o#*ect that can #e inserted into a stream to chan&e some sort of stream property! endl is one of the most common stream manipulators- thou&h others e)ist as well! To motivate some of the more comple) manipulators- let's suppose that we have a file called table-data.t+t containin& four lines of te)t- where each line consists of an inte&er value and a real num#er! 8or e)ample=

1 @0 1 2ile8 table-data.t+t
8CD GE DFMDMFD 8CCD E.D8FEF C.8G8HM 8.N0F .08808080008

Chapter 3& ,treams

0e want to write a pro&ram which reads in this data and prints it out in a ta#le- as shown here=
---------------------!----------------------!--------------------8 O 8CD O E.D8FEF E O GE O C.8G8HM C O DFMDMFD O 8.N0F G O 8CCD O 0.08808

/ere- the first column is the one1inde)ed line num#er- the second the inte&er values from the file- and the third the real1num#ered values from the file! et's #e&in #y definin& a few constants to control what the output should look like! Since there are four lines in the file- we can write
*onst int K@:L7(KE6 = G;

,nd since there are three columns*onst int K@:L5=7@:K6 = C;

"e)t- we'll pick an ar#itrary width for each column! 0e'll choose twenty characters- thou&h in principle we could pick any value as lon& as the data fit=
*onst int 5=7@:KL2(9;0 = E0;

"ow- we need to read in the ta#le data and print out the formatted ta#le! 0e'll decompose this pro#lem into two smaller steps- resultin& in the followin& source code=
.in*lude iostream) .in*lude fstream) using names$a*e std; *onst int K@:L7(KE6 = G; *onst int K@:L5=7@:K6 = C; *onst int 5=7@:KL2(9;0 = E0; int main() { <rint;able0eader(); <rint;ablePod%(); return 0; # <rint;able0eader is responsi#le for printin& out the top part of the ta#le Kthe row of dashes and plusesL and <rint;ablePod% will load the contents of the file and print them to the console!

2espite the fact that <rint;able0eader precedes <rint;ablePod% in this pro&ram- we'll #e&in #y implementin& <rint;ablePod% as it illustrates e)actly how much firepower we can &et from the stream manipulators! 0e know that we need to open the file table-data.t+t and that we'll need to read four lines of data from it- so we can #e&in writin& this function as follows=

Chapter 3& ,treams

1 @1 1

void <rint;ablePod%() { ifstream in$ut(/table-data.t+t/); "3 Ko error-*he*Bing here, but %ou should be sure to do this in an% real 3 $rogram. 3" "3 7oo$ over the lines in the file reading data. 3" for(int B = 0; B K@:L7(KE6; !!B) { "3 ... $ro*ess data ... 3" # #

.ou may have noticed that at the end of this for loop ''ve written !!B instead of B!!! There's a sli&ht difference #etween the two synta)es- #ut in this conte)t they are interchan&ea#le! 0hen we talk a#out operator overloadin& in a later chapter we'll talk a#out why it's &enerally considered #etter practice to use the prefi) increment operator instead of the postfi)! "ow- we need to read data from the file and print it as a ta#le! 0e can start #y actually readin& the values from the file- as shown here=
void <rint;ablePod%() { ifstream in$ut(/table-data.t+t/); "3 Ko error-*he*Bing here, but %ou should be sure to do this in an% real 3 $rogram. 3" "3 7oo$ over the lines in the file reading data. 3" for(int B = 0; B K@:L7(KE6; !!B) { int intJalue; double doubleJalue; in$ut )) intJalue )) doubleJalue; # #

"e)t- we need to print out the ta#le row! This is where thin&s &et tricky! 'f you'll recall- the ta#le is supposed to #e printed as three columns- each a fi)ed width- that contain the relevant data! /ow can we ensure that when we print the values to *out that we put in the appropriate amount of whitespace> Banually writin& space characters would #e difficult- so instead we'll use a stream manipulator called set' Kset widthL to force *out to pad its output with the ri&ht num#er of spaces! set' is defined in the iomani$) header file and can #e used as follows=
*out set'(80) 8CD endl;

This tells *out that the ne)t item it prints out should #e padded with spaces so that it takes up at least ten characters! Similarly*out set'(E0) /0ello there1/ endl;

0ould print out 0ello there1 with sufficient leadin& whitespace! 7y default set' pads the ne)t operation with spaces on the left side! .ou can customize this #ehavior with the left and right stream manipulators- as shown here=
*out *out A[A A[A left right set'(80) set'(80) /0ello1/ /0ello1/ A]A A]A endl; endl; "" [ 0ello1] "" [0ello1 ]

1 @; 1

Chapter 3& ,treams

7ack to our e)ample! 0e want to ensure that every ta#le column is e)actly 5=7@:KL2(9;0 spaces across! Usin& set'- this is relatively strai&htforward and can #e done as follows=
void <rint;ablePod%() { ifstream in$ut(/table-data.t+t/); "3 Ko error-*he*Bing here, but %ou should be sure to do this in an% real 3 $rogram. 3" "3 7oo$ over the lines in the file reading data. 3" for(int B = 0; B K@:L7(KE6; !!B) { int intJalue; double doubleJalue; in$ut )) intJalue )) doubleJalue; *out *out *out set'(5=7@:KL2(9;0) set'(5=7@:KL2(9;0) set'(5=7@:KL2(9;0) (B ! 8) / O /; intJalue / O /; doubleJalue endl;

# #

This produces the followin& output when run on the input file descri#ed a#ove=
8 E C G O O O O 8CD GE DFMDMFD 8CCD O O O O E.D8FEF C.8G8HM 8.N0F 0.08808

The #ody of the ta#le looks &reat- and now we *ust need to print the ta#le header- which looks like this=
---------------------!----------------------!---------------------

'f you'll notice- this is formed #y printin& twenty dashes- then the pattern -!-- another twenty dashes- the pattern -!-- and finally another twenty dashes! 0e could thus implement <rint;able0eader like this=
void <rint;able0eader() { "3 <rint the ---...---!- $attern for all but the last *olumn. 3" for(int *olumn = 0; *olumn K@:L5=7@:K6 Q 8; !!*olumn) { for(int B = 0; B 5=7@:KL2(9;0; !!B) *out A-A; *out /-!-/; # "3 Ko' $rint the ---...--- $attern for the last *olumn. 3" for(int B = 0; B 5=7@:KL2(9;0; !!B) *out A-A; "3 <rint a ne'line... thereAs nothing else on this line. 3" *out endl;

,s written there's nothin& wron& with this code and the pro&ram will work *ust fine- #ut we can simplify the implementation #y harnessin& stream manipulators! "otice that at two points we need to print out 5=7@:KL2(9;0 copies of the dash character! 0hen printin& out the ta#le #ody- we were a#le to use the set' stream manipulator to print multiple copies of the space characterQ is there some way that we can use it here to print out multiple dashes> The answer is yes- thanks to setfill! The setfill manipulator

Chapter 3& ,treams

1 @@ 1

accepts a parameter indicatin& what character to use as a fill character for set'- then chan&es the stream such that all future calls to set' pad the stream with the specified character! 8or e)ample=
*out *out setfill(A0A) set'(F) 8000 endl; "" <rints 00001000 set'(F) 8000 endl; "" <rints 00001000 be*ause of last setfill

"ote that setfill does not replace all space characters with instances of some other character! 't is only meanin&ful in con*unction with set'! 8or e)ample=
*out setfill(ARA) /6ome 6$a*es/ endl; "" <rints 6ome 6$a*es

Usin& setfill and set'- we can print out 5=7@:KL2(9;0 copies of the dash character as follows=
*out setfill(A-A) set'(5=7@:KL2(9;0) // setfill(A A);

This code is dense- so let's walk throu&h it one step at a time! The first part- setfill(A-A)- tells *out to pad all output with dashes instead of spaces! "e)t- we use set' to tell *out that the ne)t operation should take up at least 5=7@:KL2(9;0 characters! The trick is the ne)t step- printin& the empty strin&! Since the empty strin& has len&th zero and the ne)t operation will always print out at least 5=7@:KL2(9;0 characters padded with dashes- this code prints out 5=7@:KL2(9;0 dashes in a row! 8inally- since setfill permanently sets the fill character- we use setfill(A A) to undo the chan&es we made to *out! Usin& this code- we can rewrite <rint;able0eader as follows=
void <rint;able0eader() { "3 <rint the ---...---!- $attern for all but the last *olumn. 3" for(int *olumn = 0; *olumn K@:L5=7@:K6 Q 8; !!*olumn) *out setfill(A-A) set'(5=7@:KL2(9;0) // /-!-/; "3 Ko' $rint the ---...--- $attern for the last *olumn and a ne'line. 3" *out set'(5=7@:KL2(9;0) // setfill(A A) endl;

-otice that we only call setfill(A A) once, at the end o* this *#nction, since there.s no reason to clear it at each step. +lso notice that we.ve red#ced the len/th o* this *#nction dramatically by havin/ the library ta0e care o* the heavy li*tin/ *or #s. The code to print o#t a table header is now three lines lon/1 There are many stream manipulators availa#le in C++! The followin& ta#le lists some of the more commonly1used ones=
boolal$ha *out *out true endl; boolal$ha true "" =ut$ut4 8 "" =ut$ut4 true

endl;

2etermines whether or not the stream should output #oolean values as 1 and 0 or as 4true6 and 4false!6 The opposite manipulator is noboolal$ha- which reverses this #ehavior!
set'(n) *out *out 80 endl; set'(H) 80 "" =ut$ut4 80 endl; "" =ut$ut4 80

Sets the minimum width of the output for the ne)t stream operation! 'f the data doesn't meet the minimum field re5uirement- it is padded with the default fill character until it is the proper size!

1 @A 1 Common stream manipulators- contd!


he+, de*, o*t *out 80 endl; *out de* 80 *out o*t 80 *out he+ 80 *in )) he+ )) +;

Chapter 3& ,treams

"" =ut$ut4 80 endl; "" =ut$ut4 80 endl; "" =ut$ut4 8E endl; "" =ut$ut4 a "" Ieads a he+ade*imal value.

Sets the radi) on the stream to either octal K#ase EL- decimal K#ase 10L- or he)adecimal K#ase 16L! This can #e used either to format output or chan&e the #ase for input!
's m%6tream )) 's )) value;

Skips any whitespace stored in the stream! 7y default the stream e)traction operator skips over whitespace- #ut other functions like getline do not! 's can sometimes #e useful in con*unction with these other functions! 1.en 6treams o Bad 7ecause stream operations often involve transformin& data from one form into another- stream operations are not always &uaranteed to succeed! 8or e)ample- consider the followin& code snippet- which reads inte&er values from a file=
ifstream in(/in$ut.t+t/); "" Iead from in$ut.t+t for(int i = 0; i K@:L(K;6; !!i) { int value; in )) value; "3 ... $ro*ess value here ... 3" #

'f the file in$ut.t+t contains K@:L(K;6 consecutive inte&er values- then this code will work correctly! /owever- what happens if the file contains some other type of data- such as a strin& or a real num#er> 'f you try to read stream data of one type into a varia#le of another type- rather than crashin& the pro&ram or fillin& the varia#le with &ar#a&e data- the stream fails #y enterin& an error state and the value of the varia#le will not chan&e! Gnce the stream is in this error state- any su#se5uent read or write operations will automatically and silently fail- which can #e a serious pro#lem! .ou can check if a stream is in an error state with the .fail() mem#er function! 2on't let the name mislead you ( fail checks if a stream is in an error state- rather than puttin& the stream into that state! 8or e)ample- here's code to read input from *in and check if an error occurred=
int m%(nteger; *in )) m%(nteger; if(*in.fail()) { "3 ... error ... 3" #

2* a stream is in a *ail state, yo#.ll probably want to per*orm some special handlin/, possibly by reportin/ the error. 3nce yo#.ve *i4ed any problems, yo# need to tell the stream that everythin/ is o0ay by #sin/ the .*lear() member *#nction to brin/ the stream o#t o* its error state. -ote that clear won.t s0ip over the inp#t that p#t the stream into an error state5 yo# will need to e4tract this inp#t man#ally. Streams can also &o into error states if a read operation fails #ecause no data is availa#le! This occurs most commonly when readin& data from a file! et's return to the ta#le1printin& e)ample! 'n the <rint;able9ata function- we hardcoded the assumption that the file contains e)actly four lines of data!

Chapter 3& ,treams

1 @? 1

7ut what if we want to print out ta#les of ar#itrary len&th> 'n that case- we'd need to continuously read throu&h the file e)tractin& and printin& num#ers until we e)haust its contents! 0e can tell when we've run out of data #y checkin& the .fail() mem#er function after performin& a read! 'f .fail() returns truesomethin& prevented us from e)tractin& data Keither #ecause the file was malformed or #ecause there was no more dataL and we can stop loopin&! Fecall that the ori&inal code for readin& data looks like this=
void <rint;ablePod%() { ifstream in$ut(/table-data.t+t/); "3 7oo$ over the lines in the file reading data. 3" for(int B = 0; B K@:L7(KE6; !!B) { int intJalue; double doubleJalue; in$ut )) intJalue )) doubleJalue; *out *out *out set'(5=7@:KL2(9;0) set'(5=7@:KL2(9;0) set'(5=7@:KL2(9;0) (B ! 8) / O /; intJalue / O /; doubleJalue endl;

# #

The updated version of this code- which reads all of the contents of the file- is shown here=
void <rint;ablePod%() { ifstream in$ut(/table-data.t+t/); "3 7oo$ over the lines in the file reading data. 3" int ro'Kumber = 0; 'hile(true) { int intJalue; double doubleJalue; in$ut )) intJalue )) doubleJalue; if(in$ut.fail()) breaB; *out *out *out # set'(5=7@:KL2(9;0) set'(5=7@:KL2(9;0) set'(5=7@:KL2(9;0) (ro'Kumber ! 8) / O /; intJalue / O /; doubleJalue endl;

ro'Kumber!!; #

"otice that we put the main lo&ic into a 'hile(true) loop that breaBs when in$ut.fail() returns true instead of a 'hile(1in$ut.fail()) loop! These two structures may at first appear similar- #ut are 5uite different from one another! 'n a 'hile(1in$ut.fail()) loop- we only check to see if the stream encountered an error after readin& and processin& the data in the #ody of the loop! This means that the loop will e)ecute once more than it should- #ecause we don't notice that the stream malfunctioned until the top of the loop! Gn the other hand- in the a#ove loop structure K 'hile(true) plus breaBL- we stop loopin& as soon as the stream realizes that somethin& has &one awry! Confusin& these two loop structures is a common error- so #e sure that you understand why to use the 4loop1and1a1half6 idiom rather than a simple 'hile loop!

1 @6 1 A Gseful 6.ort.and

Chapter 3& ,treams

'n the a#ove code- we used the loop1and1a1half idiom to determine whether we should continue readin& and printin& data out of the file or whether we should stop loopin&! The &eneral pattern for this idiom is as follows=
'hile(true) { int intJalue; double doubleJalue; in$ut )) intJalue )) doubleJalue; if(in$ut.fail()) breaB; "3 ... $ro*ess values here ... 3" #

This code is perfectly valid- #ut it's a #it clunky! The outermost loop is a 'hile(true) loop- which means 4loop forever-6 #ut in reality the idea we want to represent is 4loop until there is no more availa#le data!6 The desi&ners of the streams li#rary anticipated this use case and provided a remarka#ly simple shorthand to alleviate this comple)ity! The a#ove code is entirely e5uivalent to
int intJalue; double doubleJalue; 'hile(in$ut )) intJalue )) doubleJalue) { "3 ... $ro*ess values here ... 3" #

"otice that the condition of the 'hile loop is now in$ut )) intJalue )) doubleJalue! Fecall that in C++- any nonzero value is interpreted as 4 true6 and any zero value is interpreted as 4 false!6 The streams li#rary is confi&ured so that most stream operations- includin& stream insertion and e)traction- yield a nonzero value if the operation succeeds and zero otherwise! This means that code such as the a#ovewhich uses the read operation as the loopin& condition- is perfectly valid! Gne particular advanta&e of this approach is that while the synta) is considera#ly more dense- the code is more intuitive! .ou can read this while loop as 4while ' can successfully read data into intJalue and doubleJalue- continue e)ecutin& the loop!6 Compared to our ori&inal implementation- this is much cleaner! This synta) shorthand is actually a special case of a more &eneral techni5ue! 'n any circumstance where a #oolean value is e)pected- it is le&al to place a stream o#*ect or a stream readHwrite operation! 0e will see this later in this chapter when we e)plore the &etline function! 1.en 6treams Do Too (uc. Consider the followin& code snippet- which prompts a user for an a&e and hourly salary=
int age; double hourl%2age; *out /<lease enter %our age4 /; *in )) age; *out /<lease enter %our hourl% 'age4 /; *in )) hourl%2age;

Chapter 3& ,treams

1 @D 1

,s mentioned a#ove- if the user enters a strin& or otherwise non1inte&er value when prompted for their a&e- the stream will enter an error state! There is another ed&e case to consider! Suppose the input is E.D8FEF! .ou would e)pect that- since this isn't an inte&er Kit's a real num#erL- the stream would &o into an error state! /owever- this isn't what happens! The first call- *in )) age- will set age to E! The ne)t call- *in )) hourl%2age- rather than promptin& the user for a value- will find the .D8FEF from the earlier input and fill in hourl%2age with that information! 2espite the fact that the input was malformed for the first prompt- the stream was a#le to partially interpret it and no error was si&naled! ,s if this wasn't #ad enou&h- suppose we have this pro&ram instead- which prompts a user for an administrator password and then asks whether the user wants to format her hard drive=
string $ass'ord; *out /Enter administrator $ass'ord4 /; *in )) $ass'ord; if($ass'ord == /$ass'ord/) { "" @se a better $ass'ord, b% the 'a%1 *out /9o %ou 'ant to erase %our hard drive (S or K)T /; *har %es=rKo; *in )) %es=rKo; if(%es=rKo == A%A) Erase0ard9rive(); #

0hat happens if someone enters $ass'ord %> The first call- *in )) $ass'ord- will read only $ass'ord! Gnce we reach the second *in read- it automatically fills in %es=rKo with the leftover %- and there &oes our hard driveR Clearly this is not what we intended! ,s you can see- readin& directly from *in is unsafe and poses more pro#lems than it solves! 'n CS1067HI we provide you with the sim$io.h li#rary primarily so you don't have to deal with these sorts of errors! 'n the ne)t section- we'll e)plore an entirely different way of readin& input that avoids the a#ove pro#lems! An Alternati;e8 getline Up to this point- we have #een readin& data usin& the stream e)traction operator- which- as you've seencan #e dan&erous! /owever- there are other functions that read data from a stream! Gne of these functions is getline- which reads characters from a stream until a newline character is encountered- then stores the read characters Kminus the newlineL in a string! getline accepts two parameters- a stream to read from and a string to write to! 8or e)ample- to read a line of te)t from the console- you could use this code=
string m%6tr; getline(*in, m%6tr);

"o matter how many words or tokens the user types on this line- #ecause getline reads until it encounters a newline- all of the data will #e a#sor#ed and stored in m%6tr! Boreover- #ecause any data the user types in can #e e)pressed as a strin&- unless your input stream encounters a read error- getline will not put the stream into a fail state! "o lon&er do you need to worry a#out stran&e 'HG ed&e casesR

1 @E 1

Chapter 3& ,treams

.ou may have noticed that the getline function acts similarly to the CS1067HI Get7ine function! This is no coincidence- and in fact the Get7ine function from sim$io.h is implemented as follows=P
string Get7ine() { string result; getline(*in, result); return result; #

,t this point- getline may seem like a silver1#ullet solution to our input pro#lems! /owever- getline has a small pro#lem when mi)ed with the stream e)traction operator! 0hen the user presses return after enterin& te)t in response to a *in prompt- the newline character is stored in the *in internal #uffer! "ormally- whenever you try to e)tract data from a stream usin& the )) operator- the stream skips over newline and whitespace characters #efore readin& meanin&ful data! This means that if you write code like this=
int first, se*ond; *in )) first; *in )) se*ond;

The newline stored in *in after the user enters a value for first is eaten #y *in #efore se*ond is read! /owever- if we replace the second call to *in with a call to getline- as shown here=
int dumm%(nt; string dumm%6tring; *in )) dumm%(nt; getline(*in, dumm%6tring); getline will return an empty strin&! 0hy> Unlike the stream e)traction operator- getline does not skip over the whitespace still remainin& in the *in stream! Conse5uently- as soon as getline is called- it will find the newline remainin& from the previous *in statement- assume the user has pressed return- and

return the empty strin&! To fi) this pro#lem- your #est option is to replace all normal stream e)traction operations with calls to li#rary functions like Get(nteger and Get7ine that accomplish the same thin&! 8ortunately- with the information in the ne)t section- you'll #e a#le to write Get(nteger and almost any GetLLLL function you'd ever need to use! 0hen we cover templates and operator overloadin& in later chapters- you'll see how to #uild a &eneric read function that can parse any sort of data from the user! 4eading 2iles wit. getline Gur treatment of getline so far has only considered usin& getline to read data from *in- #ut getline is in fact much more &eneral and can #e used to read data from any stream o#*ect- includin& file streams! To &ive a #etter feel for how the getline function works in practice- let's &o over a 5uick e)ample of how to use getline to read data from files! 'n this e)ample- we'll write a pro&ram that takes in a data file containin& some useful information and display it in a nice- pretty format! 'n particular- we'll write a pro&ram that reads a data file called 'orld-*a$itals.t+t containin& a list of all the world's countries and their capitals- then displays them to the user! 0e will assume that the 'orld-*a$itals.t+t file is formatted as follows=

P Technically- the implementation of Get7ine from sim$io.h is sli&htly different- as it checks to make sure that *in is not in an error state #efore readin&!

Chapter 3& ,treams 8ile= 'orld-*a$itals.t+t


Abu 9habi @nited Arab Emirates Abu>a Kigeria A**ra Ghana Addis Ababa Ethio$ia ...

1 @< 1

'n this file- every pair of lines represents a capital city and the country of which it is the capital! 8or e)ample- the first two lines indicate that ,#u 2ha#i is the capital of the United ,ra# Jmirates- the second two that ,#u*a is the capital of "i&eria- etc! Gur &oal is to write a pro&ram that prints this data in the followin& format=
Abu 9habi is the *a$ital of @nited Arab Emirates Abu>a is the *a$ital of Kigeria A**ra is the *a$ital of Ghana ...

/ow can we &o a#out writin& a pro&ram like this> 0ell- we can start #y openin& the file and printin& an error if we can't find it=
int main() { ifstream *a$itals(/'orld-*a$itals.t+t/) if (1*a$itals.isLo$en()) { *err /5annot find the file 'orld-*a$itals.t+t/ return -8; # "3 ... 3" #

endl;

"ow- we need to process pairs of lines in the file! Usin& the concepts from this chapter- we have two &eneral lines of attack to consider! 8irst- we could use the stream e)traction operator )) to read the data from the file! Second- we could use the getline function to read lines of te)t from the file! 'n this particular circumstance- it is not a particularly &ood idea to use the stream e)traction operator! Femem#er that the e)traction operator reads data from files one token at a time- rather than one line at a time! "ot all world capitals are a sin&le token lon& Kfor e)ample- ,#u 2ha#i or ,ddis ,#a#aL nor are all countries one token lon& Kfor e)ample- United ,ra# JmiratesL! 'f we were to try to read the file data usin& the stream e)traction operator- we would have no way of knowin& when we had read in the complete name of a capital city or country- and it would #e all #ut impossi#le to print the data out in a meanin&ful format! /owever- getline does not have this pro#lem- since getline #lindly reads lines of te)t and has no notion of whitespace1delineated tokens! Thus for this particular pro&ram- we'll use the getline function to read file data! ,s with most file readin& operations- we will need to keep loopin& until we've e)hausted all of the data in the file! This can usually #e done with the loop1and1a1half idiom! 'n our case- one possi#le version of the code is as follows=

1 A0 1
int main() { ifstream *a$itals(/'orld-*a$itals.t+t/) if (1*a$itals.isLo$en()) { *err /5annot find the file 'orld-*a$itals.t+t/ return -8; # 'hile (true) { string *a$ital, *ountr%; getline(*a$itals, *a$ital); getline(*a$itals, *ountr%); if (*a$itals.fail()) breaB; # # *out *a$ital / is the *a$ital of / *ountr%

Chapter 3& ,treams

endl;

endl;

The a#ove code creates two strin&s- *a$ital and *ountr%- and populates them with data from the file! 't then checks whether the read succeeded- and- if so- prints out the formatted data strin&! This code is perfectly correct- #ut it's clunky! The loop1and1a1half idiom is never pretty- and there has to #e a #etter way to structure this code! 8ortunately- there is a wonderful shorthand we can use to condense this code! Fecall that when usin& the stream e)traction operator ))- we could write code to the followin& effect to read data from a file and continue loopin& while the read operation succeeds=
'hile (m%6tream )) m%Jalue) { "3 ... $ro*ess m%Jalue here ... 3" #

0e can use a similar trick with getline! 'n particular- the getline function returns a nonzero value if data can #e read from a file and a zero value otherwise! Conse5uently- we can rewrite the a#ove code as follows=
int main() { ifstream *a$itals(/'orld-*a$itals.t+t/) if (1*a$itals.isLo$en()) { *err /5annot find the file 'orld-*a$itals.t+t/ return -8; #

endl;

string *a$ital, *ountr%; 'hile (getline(*a$itals, *a$ital) ?? getline(*a$itals, *ountr%)) *out *a$ital / is the *a$ital of / *ountr% endl; #

This code is considera#ly more concise than our ori&inal version and ar&ua#ly easier to read! The condition of the 'hile loop now reads 4while we can read a line from the file into *a$ital and a line from the file into *ountr%- keep e)ecutin& the loop!6 'f you ever find yourself readin& a file line1#y1line- feel free to adapt this trick into your own code ( you'll save yourself a &reat deal of typin& if you do!

Chapter 3& ,treams A 6tring Buffer8 stringstream 7efore we discuss writin& Get(nteger- we'll need to take a diversion to another type of C++ stream!

1 A1 1

Gften you will need to construct a strin& composed #oth of plain te)t and numeric or other data! 8or e)ample- suppose you wanted to call this hypothetical function=
void :essagePo+Alert(string message);

and have it display a messa&e #o) to the user informin& her that the level num#er she wanted to warp to is out of #ounds! ,t first thou&ht- you mi&ht try somethin& like
int levelKum = "3 ... 3"; :essagePo+Alert(/7evel / ! levelKum ! / is out of bounds./); "" Error

8or those of you with $ava e)perience this mi&ht seem natural- #ut in C++ this isn't le&al #ecause you can't add num#ers to strin&s Kand when you can- it's almost certainly won't do what you e)pectedQ see the chapter on C strin&sL! Gne solution to this pro#lem is to use another kind of stream o#*ect known as a stringstream- e)ported #y the sstream) header! ike console streams and file streams- stringstreams are stream o#*ects and conse5uently all of the stream operations we've covered a#ove work on stringstreams! /oweverinstead of readin& or writin& data to an e)ternal source- stringstreams store data in temporary strin& #uffers! 'n other words- you can view a stringstream as a way to create and read strin& data usin& stream operations! 8or e)ample- here is a code snippet to create a stringstream and put te)t data into it=
stringstream m%6tream; m%6tream /0ello1/ 8CD;

Gnce you've put data into a stringstream- you can retrieve the strin& you've created usin& the .str() mem#er function! Continuin& the a#ove e)ample- we can print out an error messa&e as follows=
int levelKum = "3 ... 3"; stringstream message;e+t; message;e+t /7evel / levelKum :essagePo+Alert(message;e+t.str()); / is out of bounds./;

stringstreams are an e)ample of an iostream- a stream that can perform #oth input and output! .ou can #oth insert data into a stringstream to convert the data to a strin& and e)tract data from a stringstream to convert strin& data into a different format! 8or e)ample= stringstream m%5onverter; int m%(nt; string m%6tring; double m%9ouble; m%5onverter /8CD 0ello E.D8FEF/; m%5onverter )) m%(nt )) m%6tring )) m%9ouble; "" (nsert string data "" E+tra*t mi+ed data

1 A; 1

Chapter 3& ,treams

The standard rules &overnin& stream e)traction operators still apply to stringstreams- so if you try to read data from a stringstream in one format that doesn't match the character data- the stream will fail! 0e'll e)ploit this functionality in the ne)t section! !utting it all toget.er8 1riting GetInteger Usin& the techni5ues we covered in the previous sections- we can implement a set of ro#ust user input functions alon& the lines of those provided #y sim$io.h! 'n this section we'll e)plore how to write Get(nteger- which prompts the user to enter an inte&er and returns only after the user enters valid input! Fecall from the a#ove sections that readin& an inte&er from *in can result in two types of pro#lems! 8irstthe user could enter somethin& that is not an inte&er- causin& *in to fail! Second- the user could enter too much input- such as 8CD EGN or 0ello CD- in which case the operation succeeds #ut leaves e)tra data in *in that can &ar#le future reads! 0e can immediately eliminate these sorts of pro#lems #y usin& the getline function to read input- since getline cannot put *in into a fail state and &ra#s all of the user's data- rather than *ust the first token! The main pro#lem with getline is that the input is returned as a string- rather than as formatted data! 8ortunately- usin& a stringstream- we can convert this te)t data into another format of our choice! This su&&ests an implementation of Get(nteger! 0e read data from the console usin& getline and funnel it into a stringstream! 0e then use standard stream manipulations to e)tract the inte&er from the stringstream- reportin& an error and repromptin& if una#le to do so! 0e can start writin& Get(nteger as follows=
int Get(nteger() { 'hile(true) { "" Iead in$ut until user enters valid data stringstream *onverter; *onverter Get7ine(); "3 <ro*ess data here. *out /Ietr%4 / # # =n error4 3"

,t this point- we've read in all of the data we need- and simply need to check that the data is in the proper format! ,s mentioned a#ove- there are two sorts of pro#lems we mi&ht run into ( either the data isn't an inte&er- or the data contains leftover information that isn't part of the inte&er! 0e need to check for #oth cases! Checkin& for the first turns out to #e pretty simple ( #ecause stringstreams are stream o#*ectswe can see if the data isn't an inte&er #y e)tractin& an inte&er from our stringstream and checkin& if this puts the stream into a fail state! 'f so- we know the data is invalid and can alert the user to this effect! The updated code for Get(nteger is as follows=

Chapter 3& ,treams


int Get(nteger() { 'hile(true) { "" Iead in$ut until user enters valid data stringstream *onverter; *onverter Get7ine(); "3 ;r% reading an int, *ontinue if 'e su**eeded. 3" int result; if(*onverter )) result) { "3 ... *he*B that there isnAt an% leftover data ... 3" # else *out /<lease enter an integer./ endl; # # *out /Ietr%4 /

1 A@ 1

8inally- we need to check if there's any e)tra data left over! 'f so- we need to report to the user that somethin& is wron& with the input- and can otherwise return the value we read! 0hile there are several ways to check this- one simple method is to read in a sin&le *har from the stringstream! 'f it is possi#le to do so- then we know that there must have #een somethin& in the input stream that wasn't picked up when we e)tracted an inte&er and conse5uently that the input is #ad! Gtherwise- the stream must #e out of data and will enter a fail state- si&nalin& that the user's input was valid! The final code for Get(ntegerwhich uses this trick- is shown here=
int Get(nteger() { 'hile(true) { "" Iead in$ut until user enters valid data stringstream *onverter; *onverter Get7ine(); "3 ;r% reading an int, *ontinue if 'e su**eeded. 3" int result; if(*onverter )) result) { *har remaining; if(*onverter )) remaining) "" 6omethingAs left, in$ut is invalid *out /@ne+$e*ted *hara*ter4 / remaining endl; else return result; # else *out /<lease enter an integer./ endl; *out # # /Ietr%4 /

1 AA 1 (ore To )*+lore

Chapter 3& ,treams

C++ streams are e)tremely powerful and encompass a hu&e amount of functionality! 0hile there are many more facets to e)plore- ' hi&hly recommend e)plorin& some of these topics= 4andom Access= Bost of the time- when performin& 'HG- you will access the data se5uentiallyQ that is- you will read in one piece of data- then the ne)t- etc! /owever- in some cases you mi&ht know in advance that you want to look up only a certain piece of data in a file without considerin& all of the data #efore it! 8or e)ample- a %'C archive containin& a directory structure most likely stores each compressed file at a different offset from the start of the file! Thus- if you wanted to write a pro&ram capa#le of e)tractin& a sin&le file from the archive- you'd almost certainly need the a#ility to *ump to ar#itrary locations in a file! C++ streams support this functionality with the seeBg- tellg- seeB$- and tell$ functions Kthe first two for istreams- the latter for ostreamsL! Fandom access lets you 5uickly *ump to sin&le records in lar&e data #locks and can #e useful in data file desi&n!
read and write= 0hen you write numeric data to a stream- you're actually convertin& them into

se5uences of characters that represent those num#ers! 8or e)ample- when you print out the four1 #yte value DFMDMFD8- you're usin& ei&ht #ytes to represent the data on screen or in a file ( one for each character! These e)tra #ytes can 5uickly add up- and it's actually possi#le to have on1disk representations of data that are more than twice as lar&e as the data stored in memory! To &et around this- C++ streams let you directly write data from memory onto disk without any formattin&! ,ll ostreams support a 'rite function that writes unformatted data to a stream- and istreams support read to read unformatted data from a stream into memory! 0hen used wellthese functions can cut file loadin& times and reduce disk space usa&e! 8or e)ample- The CS1067HI 7e+i*on class uses read to 5uickly load its data file into memory! !ractice !roblems /ere are some 5uestions to help you play around with the material from this chapter! Try some of these outQ you'll #e a #etter coder for the effort! 1. /ow do you write data to a file in C++> 2. 0hat does the set' manipulator do> 0hat does the setfill manipulator do> /ow do you use them> 3. 0hat is stream failure> /ow do you check for it> 4. 0hat is a stringstream> . Usin& a stringstream- write a function that converts an int into a string! !. Bodify the code for Get(nteger to create a function GetIeal that reads a real num#er from the user! /ow much did you need to modify to make this code work> $. Usin& the code for Get(nteger and the boolal$ha stream manipulator- write a function GetPoolean that waits for the user to enter 4true6 or 4false6 and returns the correspondin& #oolean value!

Chapter 3& ,treams

1 A? 1

6. 'n common usa&e- num#ers are written in decimal or base /%! This means that a strin& of di&its is interpreted as a sum of multiples of powers of ten! 8or e)ample- the num#er 1@D is 1X100 + @X10 + DX1- which is the same as 1X10; + @X101 + DX100! /owever- it is possi#le to write num#ers in other #ases as well! 8or e)ample- octal- or #ase E- encodes num#ers as sums of multiples of powers of ei&ht! 8or e)ample- 1@D in octal would #e 1XE ; + @XE1 + DXE0 Y 6A + ;A + D Y <? in decimal! P Similarly- binary- or #ase ;- uses powers of two! 0hen workin& in a particular #ase- we only use di&its from 0 up to that #ase! Thus in #ase 10 we use the di&its zero throu&h nine- while in #ase five the only di&its would #e 0- 1- ;- @- and A! This means that ?D is not a valid #ase1five num#er and <@ is not a valid octal num#er! 0hen workin& in #ases num#ered hi&her than ten- it is customary to use letters from the #e&innin& of the alpha#et as di&its! 8or e)ample- in he4adecimal- or #ase 16- one counts 0- 1- ;- !!!- <- ,- 7- C- 2- J- 8- 10! This means that @2A?J is a valid he)adecimal num#er- as is 2J,27JJ8 or 2J8,CJ2! 0rite a function 0as0e+7etters that accepts an int and returns whether or not that inte&er's he)adecimal representation contains letters! 5+int& you)ll need to use the hex and dec stream manipulators in con!unction with a stringstream Try to solve this problem without brute"$orcing it& leverage o$$ the streams library instead o$ using loops 6 7. ,lthou&h the console does not naturally lend itself to &raphics pro&rammin&- it is possi#le to draw rudimentary appro)imations of poly&ons #y printin& out multiple copies of a character at the proper location! 8or e)ample- we can draw a trian&le #y drawin& a sin&le character on one linethen three on the ne)t- five on the line after that- etc! 8or e)ample=
. ... ..... ....... .........

Usin& the set' and setfill stream manipulators- write a function 9ra';riangle that takes in an int correspondin& to the hei&ht of the trian&le and a *har representin& a character to printthen draws a trian&le of the specified hei&ht usin& that character! The trian&le should #e ali&ned so that the #ottom row starts at the #e&innin& of its line! 10. 0rite a function =$en&ile that accepts as input an ifstream #y reference and prompts the user for the name of a file! 'f the file can #e found- =$en&ile should return with the ifstream opened to read that file! Gtherwise- =$en&ile should print an error messa&e and reprompt the user! 5+int& I$ you try to open a none4istent $ile with an ifstream, the stream goes into a $ail state and you will need to use .*lear() to restore it be$ore trying again6!

P 0hy do pro&rammers always confuse /alloween and Christmas> 7ecause @1 Gct Y ;? 2ec! 8

C.a+ter '8 (ulti&2ile !rogramsI AbstractionI and t.e !re+rocessor


_________________________________________________________________________________________________________

,ll of the pro&rams we saw in the previous chapter were fairly short ( the most comple) of them ran at *ust under one hundred lines of code! 'n industrial settin&s- thou&h- pro&rams are far #i&&er- and in fact it is common for pro&rams to #e tens of millions of lines of code! 0hen code #ecomes this lon&- it is simply infeasi#le to store all of the source code in a sin&le file! 0ere all the code to #e stored in a sin&le file- it would #e ne)t to impossi#le to find a particular function or constant declaration- and it would #e incredi#ly difficult to discern any of the hi&h1level structure of the pro&ram! Conse5uently- most lar&e pro&rams are split across multiple files! 0hen splittin& a pro&ram into multiple files- there are many considerations to take into account! 8irstwhat support does C++ have for partitionin& a pro&ram across multiple files> That is- how do we communicate to the C++ compiler that several source files are all part of the same pro&ram> Second- what is the #est way to lo&ically partition the pro&ram into multiple files> 'n other words- of all of the many ways we could #reak the pro&ram apart- which is the most sensi#le> 'n this chapter- we will address these 5uestions- plus several related pro#lems that arise! 8irst- we will talk a#out the C++ compilation model ( the way that C++ source files are compiled and linked to&ether! "e)twe will e)plore the most common means for splittin& a pro*ect across files #y seein& how to write custom header and implementation files! 8inally- we will see how header files work #y discussin& the preprocessor- a pro&ram that assists the compiler in &eneratin& C++ code! T.e C99 Com+ilation (odel C++ is a compiled language- meanin& that #efore a C++ pro&ram e)ecutes- a special pro&ram called the compiler converts the C++ pro&ram directly to machine code! Gnce the pro&ram is compiled- the resultin& e)ecuta#le can #e run any num#er of times- even if the source code is nowhere to #e found! C++ compilation is a fairly comple) process that involves numerous small steps! /owever- it can &enerally #e #roken down into three lar&er processes= Preprocessing- in which code se&ments are spliced and insertedCompilation- in which code is converted to o#*ect code- and Lin*ing- in which compiled code is *oined to&ether into a final e)ecuta#le!

2urin& the preprocessin& step- a special pro&ram called the preprocessor scans over the C++ source code and applies various transformations to it! 8or e)ample- .in*lude directives are resolved to make various li#raries availa#le- special tokens like LL&(7ELL and LL7(KELL Kcovered laterL are replaced #y the file and line num#er in the source file- and .define1d constants and macros Kalso covered laterL are replaced #y their appropriate values! 'n the compilation step- the C++ source file is read in #y the compiler- optimized- and transformed into an ob!ect $ile! These o#*ect files are machine1specific- #ut usually contain machine code which e)ecutes the instructions specified in the C++ file- alon& with some e)tra information! 't's at this sta&e where the compiler will report any synta) errors you make- such as omittin& semicolons- referencin& undefined varia#les- or passin& ar&uments of the wron& types into functions! 8inally- in the linkin& phase- a pro&ram called the lin*er &athers to&ether all of the o#*ect files necessary to #uild the final e)ecuta#le- #undles them to&ether with GS1specific information- and finally produces an

1 AE 1

Chapter 7& -ulti"File Programs, Abstraction, and the Preprocessor

e)ecuta#le file that you can run and distri#ute! 2urin& this phase- the linker may report some final errors that prevent it from &eneratin& a workin& C++ pro&ram! 8or e)ample- consider the followin& C++ pro&ram=
.in*lude iostream) using names$a*e std; int &a*torial(int n); "" <rotot%$e for a fun*tion to *om$ute n1 int main() { *out &a*torial(80) return 0; # endl;

This pro&ram prototypes a function called &a*torial- calls it in main- #ut never actually defines it! Conse5uently- this pro&ram is erroneous and will not run! /owever- the error is not detected #y the compilerQ rather- it shows up as a linker error! 2urin& linkin&- the linker checks to see that every function that was prototyped and called has a correspondin& implementation! 'f it finds that some function has no implementation- it reports an error! 'n order to understand why this is- consider the followin& dia&ramwhich portrays the relationships #etween the three main phases of compilation=
C++ C++ C++ C++

Creprocessor

Creprocessor

Creprocessor

Creprocessor

Compiler

Compiler

Compiler

Compiler

1101110010 1110111100

1101110010 1110111100
inker

1101110010 1110111100

1101110010 1110111100

J)ecuta#le Cro&ram

"otice that durin& compilation- each C++ source file is treated independently the others- #ut durin& linkin& all of the files are &lued to&ether! Conse5uently- it's possi#le Kand- in fact- e)tremely commonL for a function to #e prototyped in one C++ file #ut implemented in another! 8or this reason- if the compiler sees a prototype for a function #ut no implementation- it doesn't report an error ( the definition mi&ht *ust #e in a different file it hasn't seen yet! Gnly when all of the files are pulled to&ether #y the linker is there an opportunity to check that all of the prototyped functions have some sort of implementation! 0hat does this mean for you as a C++ pro&rammer> 'n practice- this distinction usually only manifests itself in the types of error messa&es you may &et compilation! 'n particular- a pro&ram may compile perfectly well #ut fail to link #ecause you prototyped a function that was never defined! Understandin& the source of these errors and why they are reported durin& linkin& will help you dia&nose these errors more handily!

Chapter 7& -ulti"File Programs, Abstraction, and the Preprocessor ,s an e)ample- consider the followin& C++ pro&ram- which contains a su#tle error=
.in*lude iostream) .in*lude string) .in*lude **t%$e) "" &or tolo'er using names$a*e std;

1 A< 1

"3 <rotot%$e a fun*tion *alled 5onvert;o7o'er5ase, 'hi*h returns a lo'er-*ase 3 version of the in$ut string. 3" string 5onvert;o7o'er5ase(string in$ut); int main() { string m%6tring = /;0(6 (6 A 6;I(KG1/; *out 5onvert;o7o'er5ase(m%6tring); # "3 (m$lementation of 5onvert;o7o'er5ase. 3" string 5onvert;o7o'er5ase(string? in$ut) { "" Error4 9oesnAt linB; see belo' for (int B = 0; B in$ut.siUe(); !!B) in$ut[B] = tolo'er(in$ut[B]); "" tolo'er *onverts a *har to lo'er-*ase # return in$ut;

'f you compile this pro&ram in g!!- the pro&ram compiles #ut the linker will produce this mysterious error=
main.*$$4(.te+t!0+8Gd)4 undefined referen*e to V5onvert;o7o'er5ase(std44basi*Lstring *har, std44*harLtraits *har), std44allo*ator *har) ))A

'f you compile this pro&ram in Bicrosoft Tisual Studio ;00?- it will similarly compile and produce this monstrosity of an error=
error 7KWE08M4 unresolved e+ternal s%mbol /*lass std44basi*Lstring *har,stru*t std44*harLtraits *har),*lass std44allo*ator *har) ) LL*de*l 5onvert;o7o'er5ase(*lass std44basi*Lstring *har,stru*t std44*harLtraits *har),*lass std44allo*ator *har) ))/ (T5onvert;o7o'er5aseXXSATAJTY basi*LstringX9@TY*harLtraitsX9XstdXXJTYallo*atorX9XEXXstdXXJ8EXXZ) referen*ed in fun*tion Lmain

0hat's &oin& on here> This error is tricky to decipher- #ut as you can see from the hi&hli&htin& has somethin& to do with 5onvert;o7o'er5ase! et's try to see if we can &et to the root of the pro#lem! Since this is a linker error- we can immediately rule out any sort of synta) error! 'f we had made a syntactic mistake- the compiler- not the lin*er- would have cau&ht it! Boreover- since this is a linker error- it means that we somehow prototyped a function that we never &ot around to implementin&! This seems stran&e thou&h ( we prototyped the function 5onvert;o7o'er5ase and it seems like we implemented it later on in the pro&ram! The pro#lem- thou&h- is that the function we implemented doesn't match the prototype! /ere are the prototype and the implementation- reprinted ri&ht ne)t to each other=

1 ?0 1

Chapter 7& -ulti"File Programs, Abstraction, and the Preprocessor

string 5onvert;o7o'er5ase(string in$ut); "" <rotot%$e string 5onvert;o7o'er5ase(string? in$ut) { "" (m$lementation for (int B = 0; B in$ut.siUe(); !!B) in$ut[B] = tolo'er(in$ut[B]); "" tolo'er *onverts a *har to lo'er-*ase # return in$ut;

"otice that the function we've prototyped takes in a string as a parameter- while the implementation takes in a string?! That is- the prototype takes its ar&ument #y value- and the implementation #y re$erence! 7ecause these are different parameter1passin& schemes- the compiler treats the implementation as a completely different function than the one we've prototyped! Conse5uently- durin& linkin&- the linker can't locate an implementation of the prototyped function- which takes in a string #y value! ,lthou&h the functions have the same name- their si&natures are different- and they are treated as entirely different entities! To fi) this pro#lem- we must either update the prototype to match the implementation or the implementation to match the prototype! 'n this case- we'll chan&e the implementation so that it no lon&er takes in the parameter #y reference! This results in the followin& pro&ram- which compiles and links without error=
.in*lude iostream) .in*lude string) .in*lude **t%$e) "" &or tolo'er using names$a*e std; "3 <rotot%$e a fun*tion *alled 5onvert;o7o'er5ase, 'hi*h returns a lo'er-*ase 3 version of the in$ut string. 3" string 5onvert;o7o'er5ase(string in$ut); int main() { string m%6tring = /;0(6 (6 A 6;I(KG1/; *out 5onvert;o7o'er5ase(m%6tring); # "3 (m$lementation of 5onvert;o7o'er5ase. 3" string 5onvert;o7o'er5ase(string in$ut) { "" Ko' *orre*ted. for (int B = 0; B in$ut.siUe(); !!B) in$ut[B] = tolo'er(in$ut[B]); "" tolo'er *onverts a *har to lo'er-*ase return in$ut; #

Funnin& this pro&ram produces the output


this is a string!

'f you ever write a pro&ram and discover that it produces a linker error- always check to make sure that you've implemented all functions you've prototyped and that those implementations match the prototypes! Gtherwise- you mi&ht #e directin& your efforts toward catchin& a none)istent synta) error! (odularit/ and Abstraction

Chapter 7& -ulti"File Programs, Abstraction, and the Preprocessor

1 ?1 1

7ecause compilation and linkin& are separate steps in C++- it is possi#le to split up a C++ pro&ram across multiple files! To do so- we must first answer two 5uestions= 1. How do /ou s+lit a +rogram u+: That is- syntactically- how do you communicate to the C++ compiler that you want to #uild a sin&le pro&ram from a collection of files> 2. 1.at is t.e best way to s+lit a +rogram u+: 'n other words- &iven how a sin&le C++ pro&ram can #e #uilt from many files- what is the #est way to lo&ically partition the pro&ram code across those files> To answer these 5uestions- we first must take a minute to reflect on the structure of most C++ pro&rams! P 0hen writin& a C++ pro&ram to perform a particular task or solve a particular pro#lem- one usually #e&ins #y startin& with a lar&e- difficult pro#lem and then solves that pro#lem #y #reakin& it down into smaller and smaller pieces! 8or e)ample- suppose we want to write a pro&ram that allows the user to send and receive emails! 'nitially- we can think of this as one- enormous task= SendHFeceive Jmail /ow mi&ht we &o a#out #uildin& such a pro&ram> 0ell- we mi&ht #e&in #y realizin& that to write an email client- we will need to #e a#le to communicate over a network- since we'll #e transmittin& and receivin& data! ,lso- we will need some way to store the emails we've received on the user's hard disk so that she can read messa&es while offline! 0e'll also need to #e a#le to display &raphics contained in those emailsas well as create windows for displayin& content! Jach one of these tasks is itself a fairly comple) pro#lem which needs to #e solved- and so if we rethink our strate&y for writin& the email client- we mi&ht #e a#le to visualize it as follows=

SendHFeceive Jmail

"etworkin&

3raphics

Stora&e

Gf course- these tasks in of themselves mi&ht have some related su#pro#lems! 8or e)ample- when readin& and writin& from disk- we will need some tools to allow us to read and write &eneral data from diskanother set of li#raries to structure the data stored on disk- another to recover &racefully from errors- etc! /ere is one possi#le way of #reakin& each of the su#pro#lems down into smaller units=

P 'n fact- pro&rams in virtually any lan&ua&e will have the structure we're a#out to descri#e!

1 ?; 1

Chapter 7& -ulti"File Programs, Abstraction, and the Preprocessor SendHFeceive Jmail

"etworkin&

3raphics

Stora&e

TCCH'C

U2C

0indow B&mt

User 'nput

2isk Stora&e

Jrror Fecovery

'n &eneral- we write pro&rams to solve lar&e- complicated tasks #y #reakin& the task down into successively smaller and smaller pieces- then com#inin& all of those pieces #ack to&ether into a coherent whole!P 0hen usin& this setup- thou&h- one must #e e)tremely careful! Fefer to the a#ove dia&ram and notice that the a#stract pro#lem at the top depends directly on three su#pro#lems! Jach of those su#pro#lems depends in turn on even more su#pro#lems- etc! 'f the top1level pro&ram needed to e)plicitly know how each of these su#1su#pro#lems were to work- it would #e all #ut impossi#le to write! , pro&rammer tasked with desi&nin& the email pro&ram shouldn't have to understand e)actly how the networkin& module works- #ut should instead only need to know how to use it! Similarly- in order to use the windowin& module- the pro&rammer shouldn't have to understand all of its internal workin&s! 'n order for each part of the pro&ram to use its su#components without &ettin& overwhelmed #y comple)ity- there must #e some way to separate out how each su#pro#lem is solved from the way that each su#pro#lem is used! 8or e)ample- think #ack to the streams li#rary from the previous chapter! ,s you saw- you can use the ifstream and ofstream classes to read and write files! 7ut how e)actly are ifstream and ofstream put to&ether #ehind the scenes> 'nternally- these classes are incredi#ly complicated and are composed of numerous different pieces of C++ code that fit to&ether in intricate ways! 8rom your perspective- thou&h- all of this detail is irrelevantQ you only care a#out how you use these stream classes to do input and output! This distinction #etween the inner workin&s of a module Ka collection of source code that solves a pro#lemL and the way in which a client use it is an e)ample of abstraction! ,n a#straction is a simplification of a comple) o#*ect ( whether physical or in software ( that allows it to #e used without an understandin& of its underlyin& mechanism! 8or e)ample- the iChone is an incredi#ly comple) piece of hardware with #illions of transistors and &ates! Jven the simplest of tasks- such as makin& a phone call or sendin& email- tri&&ers a flurry of electrical activity in the underlyin& device! 7ut despite the implementation comple)ity- the iChone is incredi#ly easy to use #ecause the interface works at a hi&h level- with tasks like 4send te)t messa&e6 or 4play music!6 'n other words- the comple)ity of the implementation is hidden #ehind a very simple interface! 0hen desi&nin& software- you should strive to structure your software in a similar manner! 0henever you write code to solve a particular task- you should try to packa&e that code so that it communicates primarily what it does- rather than how it does it! This has several advanta&es=

P 8or those of you familiar with recursion- you mi&ht reco&nize that this &eneral structure follows a simple recursive formulation= if the pro#lem is simple enou&h- solve itQ otherwise #reak it down into smaller pieces- solve those pieces- and then &lue them all to&ether a&ain!

Chapter 7& -ulti"File Programs, Abstraction, and the Preprocessor

1 ?@ 1

6im+licit/! 'f you packa&e your code #y &ivin& it a simple interface- you make it easier for yourself and other pro&rammers to use! Boreover- if you take a #reak from a pro*ect and then return to it later- it is si&nificantly easier to resume if the interface clearly communicates its intention! )*tensibilit/! 'f you desi&n a simple- ele&ant interface- then you can chan&e the implementation as the pro&ram evolves over time without #reakin& client code! 0e'll see e)amples of this later in the chapter! 4eusabilit/! 'f your interface is sufficiently &eneric- then you may #e a#le to reuse the code you've written in multiple pro*ects! ,s an e)ample- the streams li#rary is sufficiently fle)i#le that you can use it to write #oth a simple 4/ello- 0orldR6 and a comple) pro&ram with detailed file1processin& re5uirements!

A 6am+le (odule8 6tring Gtilities To &ive you a sense for how interfaces and implementations look in software- let's take a 5uick diversion to #uild a sample C++ module to simplify common strin& operations! 'n particular- we'll write a collection of functions that simplify conversion of several common types to strin&s and vice1versa- alon& with conversions to lower1 and upper1case!P 'n C++- to create a module- we create two files ( a header $ile sayin& what functions and classes a module e)ports- and an implementation $ile containin& the implementations of those functions and classes! /eader files usually have the e)tension !h- thou&h the e)tension !hh is also sometimes used! 'mplementation files are re&ular C++ files- so they often use the e)tensions !cpp- !cc- or KoccasionallyL !C or !cpp! Traditionally- a header file and its associated implementation file will have the same name- i&norin& the e)tension! 8or e)ample- in our strin& processin& li#rary- we mi&ht name the header file strutils.h and the implementation file strutils.*$$! To &ive you a sense for what a header file looks like- consider the followin& code for strutils.h= File& strutils.h
.ifndef 6tr@tilsL(n*luded .define 6tr@tilsL(n*luded .in*lude string) using names$a*e std; string 5onvert;o@$$er5ase(string in$ut); string 5onvert;o7o'er5ase(string in$ut); string (nteger;o6tring(int value); string 9ouble;o6tring(double value); .endif

"otice that the hi&hli&hted part of this file looks *ust like a re&ular C++ file! There's a .in*lude directive to import the string type- followed #y several prototypes for functions! /owever- none of these functions are implemented ( the purpose of this file is simply to say what the module e)ports- not to provide the implementations of those functions! /owever- this header file contains some code that you have not yet seen in C++ pro&rams= the lines
P 'n other words- we'll #e writin& the strutils.h li#rary from CS1067HI!

1 ?A 1
.ifndef 6tr@tilsL(n*luded .define 6tr@tilsL(n*luded

Chapter 7& -ulti"File Programs, Abstraction, and the Preprocessor

and the line


.endif

These lines are called an include guard! ater in this chapter- we will see e)actly why they are necessary and how they work! 'n the meantime- thou&h- you should note that whenever you create a header file- you should surround that file usin& an include &uard! There are many ways to write include &uards- #ut one simple approach is as follows! 0hen creatin& a file named file.h- you should surround the file with the lines
.ifndef FileL(n*luded .define FileL(n*luded .endif

"ow that you've seen how to write a header file- let's write the matchin& implementation file! This is shown here= File& strutils.cpp
.in*lude /strutils.h/ .in*lude **t%$e) "" &or tolo'er, tou$$er .in*lude sstream) "" &or stringstream string 5onvert;o@$$er5ase(string in$ut) { for (siUeLt B = 0; B in$ut.siUe(); !!B) in$ut[B] = tou$$er(in$ut[B]); return in$ut; # string 5onvert;o@$$er5ase(string in$ut) { for (siUeLt B = 0; B in$ut.siUe(); !!B) in$ut[B] = tou$$er(in$ut[B]); return in$ut; # string (nteger;o6tring(int in$ut) { stringstream *onverter; *onverter in$ut; return *onverter.str(); # string 9ouble;o6tring(double in$ut) { stringstream *onverter; *onverter in$ut; return *onverter.str(); #

This C++ source file does not contain any new lan&ua&e constructs ( it's *ust your standard- run1of1the1mill C++ file! /owever- do note that it provides an implementation of every file e)ported in the header file! Boreover- the file #e&ins with the line
.in*lude /strutils.h/

Chapter 7& -ulti"File Programs, Abstraction, and the Preprocessor

1 ?? 1

Traditionally- an implementation file .in*ludes its correspondin& header file! 0hen we discuss the preprocessor in the latter half of this chapter- the rationale #ehind this should #ecome more clear! "ow that we've written the strutils.h".*$$ pair- we can use these functions in other C++ source files! 8or e)ample- consider the followin& simple C++ pro&ram=
.in*lude iostream) .in*lude string) .in*lude /strutils.h/ using names$a*e std; int main() { *out 5onvert;o7o'er5ase(/;0(6 (6 A 6;I(KG1/); return 0; #

This pro&ram produces the output


this is a string!

"otice that nowhere in this file did we implement or define the 5onvert;o7o'er5ase function! 't suffices to .in*lude /strutils.h/ to &ain access to this functionality! Be.ind t.e Curtain8 T.e !re+rocessor Gne of the most e)citin& parts of writin& a C++ pro&ram is pressin& the 4compile6 #utton and watchin& as your code transforms from static te)t into dynamic software! ,s mentioned earlier- this process proceeds in several steps! Gne of the first of these steps is preprocessing- where a special pro&ram called the preprocessor reads in commands called directives and modifies your code #efore handin& it off to the compiler for further analysis! .ou have already seen one of the more common preprocessor directives.in*lude- which imports additional code into your pro&ram! /owever- the preprocessor has far more functionality and is capa#le of workin& a#solute wonders on your code! 7ut while the preprocessor is powerful- it is difficult to use correctly and can lead to su#tle and comple) #u&s! The rest of this chapter introduces the preprocessor- hi&hli&hts potential sources of error- and concludes with advanced preprocessor techni5ues! , word of warnin&= the preprocessor was developed in the early days of the C pro&rammin& lan&ua&e#efore many of the more modern constructs of C and C++ had #een developed! Since then- #oth C and C++ have introduced new lan&ua&e features that have o#soleted or superseded much of the preprocessor's functionality and conse5uently you should attempt to minimize your use of the preprocessor! This is not to say- of course- that you should never use the preprocessor ( there are times when it's an e)cellent tool for the *o#- as you'll see later in the chapter ( #ut do consider other options #efore addin& a hastily1crafted directive!
#include )*+lained

'n #oth CS1067HI and CS106 - every pro&ram you've encountered has #e&un with several lines usin& the .in*lude directiveQ for e)ample- .in*lude iostream) or .in*lude /genlib.h/! 'ntuitively- these directives tell the preprocessor to import li#rary code into your pro&rams! iterally- .in*lude instructs the preprocessor to locate the specified file and to insert its contents in place of the directive itself! Thuswhen you write .in*lude /genlib.h/ at the top of your CS1067HI assi&nments- it is as if you had copied and pasted the contents of genlib.h into your source file! These header files usually contain

1 ?6 1

Chapter 7& -ulti"File Programs, Abstraction, and the Preprocessor

prototypes or implementations of the functions and classes they e)port- which is why the directive is necessary to access other li#raries!

Chapter 7& -ulti"File Programs, Abstraction, and the Preprocessor

1 ?D 1

.ou may have noticed that when .in*lude1in& CS1067HI1specific li#raries- you've surrounded the name of the file in dou#le 5uotes Ke!&! /genlib.h/L- #ut when referencin& C++ standard li#rary componentsyou surround the header in an&le #rackets Ke!&! iostream)L! These two different forms of .in*lude instruct the preprocessor where to look for the specified file! 'f a filename is surrounded in an&le #racketsthe preprocessor searches for it a compiler1specific directory containin& C++ standard li#rary files! 0hen filenames are in 5uotes- the preprocessor will look in the current directory!
.in*lude is a preprocessor directive- not a C++ statement- and is su#*ect to a different set of synta) restrictions than normal C++ code! 8or e)ample- to use .in*lude Kor any preprocessor directive- for that

matterL- the directive must #e the first non1whitespace te)t on its line! 8or e)ample- the followin& is ille&al=
*out .in*lude iostream) endl; "" Error4 .in*lude must start a line.

Second- #ecause .in*lude is a preprocessor directive- not a C++ statement- it must not end with a semicolon! That is- .in*lude iostream); will pro#a#ly cause a compiler error or warnin&! 8inally- the entire .in*lude directive must appear on a sin&le line- so the followin& code will not compile=
.in*lude iostream) "" Error4 :ulti-line $re$ro*essor dire*tives are illegal.

The #define Directive Gne of the most commonly used Kand a#usedL preprocessor directives is .define- the e5uivalent of a 4search and replace6 operation on your C++ source files! 0hile .in*lude splices new te)t into an e)istin& C++ source file- .define replaces certain te)t strin&s in your C++ file with other values! The synta) for .define is
.define phrase replacement

,fter encounterin& a .define directive- whenever the preprocessor find phrase in your source code- it will replace it with replacement! 8or e)ample- consider the followin& pro&ram=
.define :SL5=K6;AK; 8CD int main() { int + = :SL5=K6;AK; - C; return 0; #

The first line of this pro&ram tells the preprocessor to replace all instances of :SL5=K6;AK; with the phrase 8CD! Conse5uently- when the preprocessor encounters the line
int + = :SL5=K6;AK; - C;

't will transform it to read


int + = 13 - C;

So + will take the value 1@A!

1 ?E 1

Chapter 7& -ulti"File Programs, Abstraction, and the Preprocessor

7ecause .define is a preprocessor directive and not a C++ statement- its synta) can #e confusin&! 8or e)ample- .define determines the stop of the phrase portion of the statement and the start of the replacement portion #y the position of the first whitespace character! Thus- if you write
.define ;2= 2=I96 8CD

The preprocessor will interpret this as a directive to replace the phrase ;2= with 2=I96 8CD- which is pro#a#ly not what you intended! The replacement portion of the .define directive consists of all te)t after phrase that precedes the newline character! Conse5uently- it is le&al to write statements of the form .define phrase without definin& a replacement! 'n that case- when the preprocessor encounters the specified phrase in your code- it will replace it with nothin&ness- effectively removin& it! "ote that the preprocessor treats C++ source code as se5uences of strin&s- rather than representations of hi&her1level C++ constructs! 8or e)ample- the preprocessor treats int + = 8CD as the strin&s 4int-6 4+-6 4=-6 and 48CD6 rather than a statement creatin& a varia#le + with value 8CD!P 't may help to think of the preprocessor as a scanner that can read strin&s and reco&nize characters #ut which has no understandin& whatsoever of their meanin&s- much in the same way a native Jn&lish speaker mi&ht #e a#le to split Czech te)t into individual words without comprehendin& the source material! That the preprocessor works with te)t strin&s rather than lan&ua&e concepts is a source of potential pro#lems! 8or e)ample- consider the followin& .define statements- which define mar&ins on a pa&e=
.define 7E&;L:AIG(K 800 .define I(G0;L:AIG(K 800 .define 65A7E .H "3 ;otal margin is the sum of the left and right margins, multi$lied b% some 3 s*aling fa*tor. 3" .define ;=;A7L:AIG(K 7E&;L:AIG(K 3 65A7E ! I(G0;L:AIG(K 3 65A7E

0hat happens if we write the followin& code>


int + = E 3 ;=;A7L:AIG(K;

'ntuitively- this should set + to twice the value of ;=;A7L:AIG(K- #ut unfortunately this is not the case! et's trace throu&h how the preprocessor will e)pand out this e)pression! 8irst- the preprocessor will e)pand ;=;A7L:AIG(K to 7E&;L:AIG(K 3 65A7E ! I(G0;L:AIG(K 3 65A7E- as shown here=
int + = E 3 7E&;L:AIG(K 3 65A7E ! I(G0;L:AIG(K 3 65A7E;

'nitially- this may seem correct- #ut look closely at the operator precedence! C++ interprets this statement as
int + = (E 3 7E&;L:AIG(K 3 65A7E) ! I(G0;L:AIG(K 3 65A7E;

Father the e)pected


int + = E 3 (7E&;L:AIG(K 3 65A7E ! I(G0;L:AIG(K 3 65A7E);

P Technically speakin&- the preprocessor operates on 4preprocessor tokens-6 which are sli&htly different from the whitespace1differentiated pieces of your code! 8or e)ample- the preprocessor treats strin& literals containin& whitespace as a sin&le o#*ect rather than as a collection of smaller pieces!

Chapter 7& -ulti"File Programs, Abstraction, and the Preprocessor

1 ?< 1

,nd the computation will #e incorrect! The pro#lem is that the preprocessor treats the replacement for ;=;A7L:AIG(K as a strin&- not a mathematical e)pression- and has no concept of operator precedence! This sort of error ( where a .defined constant does not interact properly with arithmetic e)pressions ( is a common mistake! 8ortunately- we can easily correct this error #y addin& additional parentheses to our .define! et's rewrite the .define statement as
.define ;=;A7L:AIG(K (7E&;L:AIG(K 3 65A7E ! I(G0;L:AIG(K 3 65A7E)

0e've surrounded the replacement phrase with parentheses- meanin& that any arithmetic operators applied to the e)pression will treat the replacement strin& as a sin&le mathematical value! "ow- if we write
int + = E 3 ;=;A7L:AIG(K;

't e)pands out to


int + = E 3 (7E&;L:AIG(K 3 65A7E ! I(G0;L:AIG(K 3 65A7E);

0hich is the computation we want! 'n &eneral- if you .define a constant in terms of an e)pression applied to other .defined constants- make sure to surround the resultin& e)pression in parentheses! ,lthou&h this e)pression is certainly more correct than the previous one- it too has its pro#lems! 0hat if we redefine 7E&;L:AIG(K as shown #elow>
.define 7E&;L:AIG(K E00 Q 800

"ow- if we write
int + = E 3 ;=;A7L:AIG(K

't will e)pand out to


int + = E 3 (7E&;L:AIG(K 3 65A7E ! I(G0;L:AIG(K 3 65A7E);

0hich in turn e)pands to


int + = E 3 (E00 Q 800 3 .H ! 800 3 .H)

0hich yields the incorrect result #ecause (E00 Q 800 3 .H ! 800 3 .H) is interpreted as
(E00 Q (800 3 .H) ! 800 3 .H)

Father than the e)pected


((E00 Q 800) 3 .H ! 800 3 .H)

The pro#lem is that the .defined statement itself has an operator precedence error! ,s with last time- to fi) this- we'll add some additional parentheses to the e)pression to yield
.define ;=;A7L:AIG(K ((7E&;L:AIG(K) 3 (65A7E) ! (I(G0;L:AIG(K) 3 (65A7E))

This corrects the pro#lem #y ensurin& that each .defined su#e)pression is treated as a complete entity when used in arithmetic e)pressions! 0hen writin& a .define e)pression in terms of other .defines-

1 60 1

Chapter 7& -ulti"File Programs, Abstraction, and the Preprocessor

make sure that you take this into account- or chances are that your constant will not have the correct value! ,nother potential source of error with .define concerns the use of semicolons! 'f you terminate a .define statement with a semicolon- the preprocessor will treat the semicolon as part of the replacement phrase- rather than as an 4end of statement6 declaration! 'n some cases- this may #e what you want- #ut most of the time it *ust leads to frustratin& de#u&&in& errors! 8or e)ample- consider the followin& code snippet=
.define :SL5=K6;AK; 8CD; "" =o$s-- un'anted semi*olon1 int + = :SL5=K6;AK; 3 C;

2urin& preprocessin&- the preprocessor will convert the line int + = :SL5=K6;AK; 3 C to read
int + = 8CD; 3 C;

This is not le&al C++ code and will cause a compile1time error! /owever- #ecause the pro#lem is in the preprocessed code- rather than the ori&inal C++ code- it may #e difficult to track down the source of the error! ,lmost all C++ compilers will &ive you an error a#out the statement 3 C rather than a malformed .define! ,s you can tell- usin& .define to define constants can lead to su#tle and difficult1to1track #u&s! Conse5uently- it's stron&ly preferred that you define constants usin& the *onst keyword! 8or e)ampleconsider the followin& *onst declarations=
*onst *onst *onst *onst int + int int int int = E 7E&;L:AIG(K = E00 - 800; I(G0;L:AIG(K = 800; 65A7E = .H; ;=;A7L:AIG(K = 7E&;L:AIG(K 3 65A7E ! I(G0;L:AIG(K 3 65A7E; 3 ;=;A7L:AIG(K;

Jven thou&h we've used mathematical e)pressions inside the *onst declarations- this code will work as e)pected #ecause it is interpreted #y the C++ compiler rather than the preprocessor! Since the compiler understands the meaning of the sym#ols E00 Q 800- rather than *ust the characters themselves- you will not need to worry a#out stran&e operator precedence #u&s! Include uards )*+lained Jarlier in this chapter when we covered header files- you saw that when creatin& a header file- you should surround the header file usin& an include guard! 0hat is the purpose of the include &uard> ,nd how does it work> To answer this 5uestion- let's see what happens when a header file lacks an include &uard! Suppose we make the followin& header file- m%stru*t.h- which defines a stru*t called :%6tru*t= File& mystruct.h
stru*t :%6tru*t { int +; double %; *har U; #;

0hat happens when we try to compile the followin& pro&ram>

Chapter 7& -ulti"File Programs, Abstraction, and the Preprocessor


.in*lude /m%stru*t.h/ .in*lude /m%stru*t.h/ "" .in*lude the same file t'i*e int main() { return 0; #

1 61 1

This code looks innocuous- #ut produces a compile1time error complainin& a#out a redefinition of stru*t :%6tru*t! The reason is simple ( when the preprocessor encounters each .in*lude statement- it copies the contents of m%stru*t.h into the pro&ram without checkin& whether or not it has already included the file! Conse5uently- it will copy the contents of m%stru*t.h into the code twice- and the resultin& code looks like this=
stru*t :%6tru*t { int +; double %; *har U; #; stru*t :%6tru*t {"" int +; double %; *har U; #; int main() { return 0; #

-- Error o**urs here

The indicated line is the source of our compiler error ( we've dou#ly1defined stru*t :%6tru*t! To solve this pro#lem- you mi&ht think that we should simply have a policy of not .in*lude1in& the same file twice! 'n principle this may seem easy- #ut in a lar&e pro*ect where several files each .in*lude each other- it may #e possi#le for a file to indirectly .in*lude the same file twice! Somehow- we need to prevent this pro#lem from happenin&! The pro#lem we're runnin& into stems from the fact that the preprocessor has no memory a#out what it has done in the past! Somehow- we need to &ive the preprocessor instructions of the form 4if you haven't already done so- .in*lude the contents of this file!6 8or situations like these- the preprocessor supports conditional e)pressions! $ust as a C++ pro&ram can use if !!! else if !!! else to chan&e pro&ram flow #ased on varia#les- the preprocessor can use a set of preprocessor directives to conditionally include a section of code #ased on .defined values! There are several conditional structures #uilt into the preprocessor- the most versatile of which are .if.elif- .else- and .endif! ,s you mi&ht e)pect- you use these directives accordin& to the pattern
.if statement ... .elif another-statement ... .elif yet-another-statement ... .else ... .endif

There are two details we need to consider here! 8irst- what sorts of e)pressions can these preprocessor directives evaluate> 7ecause the preprocessor operates #efore the rest of the code has #een compiled-

1 6; 1

Chapter 7& -ulti"File Programs, Abstraction, and the Preprocessor

preprocessor directives can only refer to .defined constants- inte&er values- and arithmetic and lo&ical e)pressions of those values! /ere are some e)amples- supposin& that some constant :SL5=K6;AK; is defined to A;=
.if .if .if .if :SL5=K6;AK; ) 8CD "" 7egal :SL5=K6;AK; 3 GE == :SL5=K6;AK; "" 7egal s[rt(:SL5=K6;AK;) G "" (llegal, *annot *all fun*tion s[rt :SL5=K6;AK; == C.8G "" (llegal, *an onl% use integral values

'n addition to the a#ove e)pressions- you can use the defined predicate- which takes as a parameter the name of a value that may have previously #een .defined! 'f the constant has #een .defined- defined evaluates to 8Q otherwise it evaluates to 0! 8or e)ample- if :SL5=K6;AK; has #een previously .defined and =;0EIL5=K6;AK; has not- then the followin& e)pressions are all le&al=
.if defined(:SL5=K6;AK;) "" Evaluates to true. .if defined(=;0EIL5=K6;AK;) "" Evaluates to false. .if 1defined(:SL5=K6;AK;) "" Evaluates to false.

"ow that we've seen what sorts of e)pressions we can use in preprocessor conditional e)pressions- what is the e$$ect of these constructs> Unlike re&ular if statements- which chan&e control flow at e)ecutionpreprocessor conditional e)pressions determine whether pieces of code are included in the resultin& source file! 8or e)ample- consider the followin& code=
.if defined(A) *out /A is .elif defined(P) *out /P is .elif defined(5) *out /5 is .else *out /Kone .endif defined./ defined./ defined./ endl; endl; endl; endl;

of A, P, or 5 is defined./

/ere- when the preprocessor encounters these directives- whichever of the conditional e)pressions evaluates to true will have its correspondin& code #lock included in the final pro&ram- and the rest will #e i&nored! 8or e)ample- if A is defined- this entire code #lock will reduce down to
*out /A is defined./ endl;

,nd the rest of the code will #e i&nored! Gne interestin& use of the .if ... .endif construct is to comment out #locks of code! Since C++ interprets all nonzero values as true and zero as false- surroundin& a #lock of code in a .if 0 !!! .endif #lock causes the preprocessor to eliminate that #lock! Boreover- unlike the traditional "3 !!! 3" comment type- preprocessor directives can #e nested- so removin& a #lock of code usin& .if 0 !!! .endif doesn't run into the same pro#lems as commentin& the code out with "3 !!! 3"! 'n addition to the a#ove conditional directives- C++ provides two shorthand directives- .ifdef and .ifndef! .ifdef Kif definedL is a directive that takes as an ar&ument a sym#ol and evaluates to true if the sym#ol has #een .defined! Thus the directive .ifdef symbol is completely e5uivalent to .if defined(symbol)! C++ also provides .ifndef Kif not definedL- which acts as the opposite of .ifdefQ .ifndef symbol is e5uivalent to .if 1defined(symbol)! ,lthou&h these directives are strictly weaker than the more &eneric .if- it is far more common in practice to see .ifdef and .ifndef rather than .if defined and .if 1defined- primarily #ecause they are more concise!

Chapter 7& -ulti"File Programs, Abstraction, and the Preprocessor

1 6@ 1

Usin& the conditional preprocessor directives- we can solve the pro#lem of dou#le1includin& header files! et's return to our e)ample with .in*lude /m%stru*t .h/ appearin& twice in one file! /ere is a sli&htly modified version of the m%stru*t.h file that introduces some conditional directives= File& mystruct.h 5version 16
.ifndef :%6tru*tL(n*luded .define :%6tru*tL(n*luded stru*t :%6tru*t { int +; double %; *har U; #; .endif

/ere- we've surrounded the entire file in a #lock .ifndef :%6tru*tL(n*luded !!! .endif! The specific name :%&ileL(n*luded is not particularly important- other than the fact that it is uni5ue to the m%file.h file! 0e could have *ust as easily chosen somethin& like .ifndef sdfCMHEDdBbE or another uni5ue name- #ut the custom is to choose a name determined #y the file name! 'mmediately after this .ifndef statement- we .define the constant we are considerin& inside the .ifndef! To see e)actly what effect this has on the code- let's return to our ori&inal source file- reprinted #elow=
.in*lude /m%stru*t.h/ .in*lude /m%stru*t.h/ "" .in*lude the same file t'i*e int main() { return 0; #

0ith the modified version of m%stru*t.h- this code e)pands out to


.ifndef :%6tru*tL(n*luded .define :%6tru*tL(n*luded stru*t :%6tru*t { int +; double %; *har U; #; .endif .ifndef :%6tru*tL(n*luded .define :%6tru*tL(n*luded stru*t :%6tru*t { int +; double %; *har U; #; .endif int main() { return 0; #

1 6A 1

Chapter 7& -ulti"File Programs, Abstraction, and the Preprocessor

"ow- as the preprocessor #e&ins evaluatin& the .ifndef statements- the first .ifndef !!! .endif #lock from the header file will #e included since the constant :%6tru*tL(n*luded hasn't #een defined yet! The code then .defines:%6tru*tL(n*luded- so when the pro&ram encounters the second .ifndef #lockthe code inside the .ifndef !!! .endif #lock will not #e included! Jffectively- we've ensured that the contents of a file can only #e .in*luded once in a pro&ram! The net pro&ram thus looks like this=
stru*t :%6tru*t { int +; double %; *har U; #; int main() { return 0; #

0hich is e)actly what we wanted! This techni5ue- known as an include guard- is used throu&hout professional C++ code- and- in fact- the #oilerplate .ifndef A .define A .endif structure is found in virtually every header file in use today! 0henever writin& header files- #e sure to surround them with the appropriate preprocessor directives! (acros Gne of the most common and comple) uses of the preprocessor is to define macros- compile1time functions that accepts parameters and output code! 2espite the surface similarity- however- preprocessor macros and C++ functions have little in common! C++ functions represent code that e)ecutes at runtime to manipulate data- while macros e)pand out into newly1&enerated C++ code durin& preprocessin&! To create macros- you use an alternative synta) for .define that specifies a parameter list in addition to the constant name and e)pansion! The synta) looks like this=
.define macroname(parameter1, parameter2, ... , parameterN) macro-body*

"ow- when the preprocessor encounters a call to a function named macroname- it will replace it with the te)t in macro-body! 8or e)ample- consider the followin& macro definition=
.define <7@6L=KE(+) ((+) ! 8)

"ow- if we write
int + = <7@6L=KE(8CD);

The preprocessor will e)pand this code out to


int + = ((8CD) ! 8);

So + will have the value 1@E! 'f you'll notice- unlike C++ functions- preprocessor macros do not have a return value! Bacros e)pand out into C++ code- so the 4return value6 of a macro is the result of the e)pressions it creates! 'n the case of <7@6L=KE- this is the value of the parameter plus one #ecause the replacement is interpreted as a

P "ote that when usin& .define- the openin& parenthesis that starts the ar&ument list must not #e preceded #y whitespace! Gtherwise- the preprocessor will treat it as part of the replacement phrase for a .defined constant!

Chapter 7& -ulti"File Programs, Abstraction, and the Preprocessor

1 6? 1

mathematical e)pression! /owever- macros need not act like C++ functions! Consider- for e)ample- the followin& macro=
.define :AWEL&@K5;(=K(fnKame) void fnKame()

"ow- if we write the followin& C++ code=


:AWEL&@K5;(=K(:%&un*tion) { *out /;his is a fun*tion1/ # endl;

The :AWEL&@K5;(=K macro will convert it into the function definition


void :%&un*tion() { *out /;his is a fun*tion1/ # endl;

,s you can see- this is entirely different than the <7@6L=KE macro demonstrated a#ove! 'n &eneral- a macro can #e e)panded out to any te)t and that te)t will #e treated as thou&h it were part of the ori&inal C++ source file! This is a mi)ed #lessin&! 'n many cases- as you'll see later in the chapter- it can #e e)ceptionally useful! /owever- as with other uses of .define- macros can lead to incredi#ly su#tle #u&s that can #e difficult to track down! Cerhaps the most famous e)ample of macros &one wron& is this :AR macro=
.define :AR(a, b) ((a) ) (b) T (a) 4 (b))

/ere- the macro takes in two parameters and uses the T4 operator to choose the lar&er of the two! 'f you're not familiar with the T4 operator- the synta) is as follows=
e+$ression ! result-if-true " result-if-false

'n our case- ((a) ) (b) T (a) 4 (b)) evaluates the e)pression (a) ) (b)! 'f the statement is truethe value of the e)pression is (a)Q otherwise it is (b)! ,t first- this macro mi&ht seem innocuous and in fact will work in almost every situation! 8or e)ample=
int + = :AR(800, E00);

J)pands out to
int + = ((800) ) (E00) T (800) 4 (E00));

0hich assi&ns + the value E00! /owever- what happens if we write the followin&>
int + = :AR(:%&n8(), :%&nE());

This e)pands out to


int + = ((:%&n8()) ) (:%&nE()) T (:%&n8()) 4 (:%&nE()));

0hile this will assi&n + the lar&er of :%&n8() and :%&nE()- it will not evaluate the parameters only onceas you would e)pect of a re&ular C++ function! ,s you can see from the e)pansion of the :AR macro- the functions will #e called once durin& the comparison and possi#ly twice in the second half of the statement!

1 66 1

Chapter 7& -ulti"File Programs, Abstraction, and the Preprocessor

'f :%&n8() or :%&nE() are slow- this is inefficient- and if either of the two have side effects Kfor e)amplewritin& to disk or chan&in& a &lo#al varia#leL- the code will #e incorrect! The a#ove e)ample with :AR illustrates an important point when workin& with the preprocessor ( in &eneral- C++ functions are safer- less error1prone- and more reada#le than preprocessor macros! 'f you ever find yourself wantin& to write a macro- see if you can accomplish the task at hand with a re&ular C++ function! 'f you can- use the C++ function instead of the macro ( you'll save yourself hours of de#u&&in& ni&htmares! Inline 2unctions Gne of the motivations #ehind macros in pure C was pro&ram efficiency from inlining! 8or e)ampleconsider the :AR macro from earlier- which was defined as
.define :AR(a, b) ((a) ) (b) T (a) 4 (b))

'f we call this macro- then the code for selectin& the ma)imum element is directly inserted at the spot where the macro is used! 8or e)ample- the followin& code=
int m%(nt = :AR(one, t'o);

J)pands out to
int m%(nt = ((one) ) (t'o) T (one) 4 (t'o));

0hen the compiler sees this code- it will &enerate machine code that directly performs the test! 'f we had instead written :AR as a re&ular function- the compiler would pro#a#ly implement the call to :AR as follows= 1. Call the function called :AR Kwhich actually performs the comparisonL 2. Store the result in the varia#le m%(nt! This is considera#ly less efficient than the macro #ecause of the time re5uired to set up the function call! 'n computer science *ar&on- the macro is inlined #ecause the compiler places the contents of the 4function6 at the call site instead of insertin& an indirect *ump to the code for the function! 'nlined functions can #e considera#ly more efficient that their non1inline counterparts- and so for many years macros were the preferred means for writin& utility routines! 7*arne Stroustrup is particularly opposed to the preprocessor #ecause of its idiosyncrasies and potential for errors- and to entice pro&rammers to use safer lan&ua&e features developed the inline keywordwhich can #e applied to functions to su&&est that the compiler automatically inline them! 'nline functions are not treated like macros ( they're actual functions and none of the ed&e cases of macros apply to them ( #ut the compiler will try to safely inline them if at all possi#le! 8or e)ample- the followin& :a+ function is marked inline- so a reasona#ly &ood compiler should perform the same optimization on the :a+ function that it would on the :AR macro=
inline int :a+(int one, int t'o) { return one ) t'o T one 4 t'o; #

The inline keyword is only a su&&estion to the compiler and may #e i&nored if the compiler deems it either too difficult or too costly to inline the function! /owever- when writin& short functions it sometimes helps to mark the function inline to improve performance!

Chapter 7& -ulti"File Programs, Abstraction, and the Preprocessor A #define Cautionar/ Tale

1 6D 1

.define is a powerful directive that ena#les you to completely transform C++! /owever- many CHC++ e)perts a&ree that you should not use .define unless it is a#solutely necessary! Creprocessor macros and constants o#fuscate code and make it harder to de#u&- and with a few cryptic .defines veteran C++

pro&rammers will #e at a loss to understand your pro&rams! ,s an e)ample- consider the followin& codewhich references an e)ternal file m%defines.h=
.in*lude /m%defines.h/ =n*e u$on a time a little bo% tooB a 'alB in a $arB 0e (the *hild) found a small stone and thre' it (the stone) in a $ond ;he end

Surprisin&ly- and worryin&ly- it is possi#le to make this code compile and run- provided that m%defines.h contains the proper .defines! 8or e)ample- here's one possi#le m%defines.h file that makes the code compile= File& mydefines.h
.ifndef m%definesLin*luded .define m%definesLin*luded .in*lude iostream) using names$a*e std; .define .define .define .define .define .define .define .define .define .define .define .define .define .define .define .define .define .define .define .define .define .define .endif =n*e u$on a time u$on little bo% tooB u$on 'alB in 'alB the $arB a 0e(n) n :%&un*tion(n +) *hild int found { small return stone +; and in thre' # it(n) int main() { $ond *out :%&un*tion(8CD) end return 0; # ;he the

endl;

,fter preprocessin& Kand some whitespace formattin&L- this yields the pro&ram

1 6E 1
.in*lude iostream) using names$a*e std; int :%&un*tion(int +) { return +; # int main() { *out :%&un*tion(8CD) return 0; #

Chapter 7& -ulti"File Programs, Abstraction, and the Preprocessor

endl;

0hile this e)ample is admittedly a de&enerate case- it should indicate e)actly how disastrous it can #e for your pro&rams to misuse .defined sym#ols! Cro&rammers e)pect certain structures when readin& C++ code- and #y o#scurin& those structures #ehind walls of .defines you will confuse people who have to read your code! 0orse- if you step away from your code for a short time Ksay- a week or a monthL- you may very well return to it with a#solutely no idea how your code operates! Conse5uently- when workin& with .define- always #e sure to ask yourself whether or not you are improvin& the reada#ility of your code! Ad;anced !re+rocessor Tec.niJues The previous section ended on a rather &rim note- &ivin& an e)ample of preprocessor usa&e &one awry! 7ut to entirely eschew the preprocessor in favor of other lan&ua&e features would also #e an error! 'n several circumstances- the preprocessor can perform tasks that other C++ lan&ua&e features cannot accomplish! The remainder of this chapter e)plores where the preprocessor can #e an invalua#le tool for solvin& pro#lems and points out several stren&ths and weaknesses of preprocessor1#ased approaches! 6+ecial !re+rocessor Kalues The preprocessor has access to several special values that contain information a#out the state of the file currently #ein& compiled! The values act like .defined constants in that they are replaced whenever encountered in a pro&ram! 8or e)ample- the values LL9A;ELL and LL;(:ELL contain strin& representations of the date and time that the pro&ram was compiled! Thus- you can write an automatically1&enerated 4a#out this pro&ram6 function usin& synta) similar to this=
string GetAbout(nformation() { stringstream result; result /;his $rogram 'as *om$iled on / result / at time / LL;(:ELL; return result.str(); #

LL9A;ELL;

Similarly- there are two other values- LL7(KELL and LL&(7ELL- which contain the current line num#er and the name of the file #ein& compiled! 0e'll see an e)ample of where LL7(KELL and LL&(7ELL can #e useful later in this chapter! 6tring (ani+ulation 2unctions 0hile often dan&erous- there are times where macros can #e more powerful or more useful than re&ular C++ functions! Since macros work with source1level te)t strin&s instead of at the C++ lan&ua&e level- some pieces of information are availa#le to macros that are not accessi#le usin& other C++ techni5ues! 8or e)ample- let's return to the :AR macro we used in the previous chapter=
.define :AR(a, b) ((a) ) (b) T (a) 4 (b))

Chapter 7& -ulti"File Programs, Abstraction, and the Preprocessor

1 6< 1

/ere- the ar&uments a and b to :AR are passed #y string ( that is- the ar&uments are passed as the strin&s that compose them! 8or e)ample- :AR(80, 8H) passes in the value 80 not as a numeric value ten- #ut as the character 8 followed #y the character 0! The preprocessor provides two different operators for manipulatin& the strin&s passed in as parameters! 8irst is the stringi8ing operator- represented #y the . sym#ol- which returns a 5uoted- C strin& representation of the parameter! 8or e)ample- consider the followin& macro=
.define <I(K;=@;(n) *out .n / has value / (n) endl

/ere- we take in a sin&le parameter- n! 0e then use the strin&izin& operator to print out a strin& representation of n- followed #y the value of the e)pression n! 8or e)ample- &iven the followin& code snippet=
int + = 8CD; <I(K;=@;(+ 3 GE);

,fter preprocessin&- this yields the C++ code


int + = 8CD; *out /+ 3 GE/ / has value / (+ 3 GE) endl;

"ote that after the a#ove pro&ram has #een compiled from C++ to machine code- any notions of the ori&inal varia#le + or the individual e)pressions makin& up the pro&ram will have #een completely eliminated- since varia#les e)ist only at the C++ level! /owever- throu&h the strin&izin& operator- it is possi#le to preserve a strin& version of portions of the C++ source code in the final pro&ram- as demonstrated a#ove! This is useful when writin& dia&nostic functions- as you'll see later in this chapter! The second preprocessor strin& manipulation operator is the string concatenation operator- also known as the to*en"pasting operator! This operator- represented #y ..- takes the strin& value of a parameter and concatenates it with another strin&! 8or e)ample- consider the followin& macro=
.define 9E57AIEL:SLJAI(t%$e) t%$e m%L..t%$e

The purpose of this macro is to allow the user to specify a type Kfor e)ample- intL- and to automatically &enerate a varia#le declaration of that type whose name is m%Ltype- where type is the parameter type /ere- we use the .. operator to take the name of the type and concatenate it with the strin& m%L! Thus&iven the followin& macro call=
9E57AIEL:SLJAI(int);

The preprocessor would replace it with the code


int m%Lint;

"ote that when workin& with the token1pastin& operator- if the result of the concatenation does not form a sin&le C++ token Ka valid operator or nameL- the #ehavior is undefined! 8or e)ample- callin& 9E57AIEL:SLJAI(*onst int) will have undefined #ehavior- since concatenatin& the strin&s m%L and *onst int does not yield a sin&le strin& Kthe result is *onst int m%L*onst intL! Ad;anced !re+rocessor Tec.niJues8 T.e F (acro Trick 7ecause the preprocessor &ives C++ pro&rams access to their own source code at compile1time- it is possi#le to harness the preprocessor to do su#stantial code &eneration at compile1time! Gne uncommon

1 D0 1

Chapter 7& -ulti"File Programs, Abstraction, and the Preprocessor

pro&rammin& techni5ue that uses the preprocessor is known as the 9 -acro tric*- a way to specify data in one format #ut have it availa#le in several formats! 7efore e)plorin& the I Bacro trick- we need to cover how to redefine a macro after it has #een declared! $ust as you can define a macro #y usin& .define- you can also undefine a macro usin& .undef! The .undef preprocessor directive takes in a sym#ol that has #een previously .defined and causes the preprocessor to i&nore the earlier definition! 'f the sym#ol was not already defined- the .undef directive has no effect #ut is not an error! 8or e)ample- consider the followin& code snippet=
.define :SL(K; 8CD int + = :SL(K;; "" :SL(K; is re$la*ed .undef :SL(K;; int :SL(K; = GE; "" :SL(K; not re$la*ed

The preprocessor will rewrite this code as


int + = 8CD; int :SL(K; = GE;

,lthou&h :SL(K; was once a .defined constant- after encounterin& the .undef statement- the preprocessor stopped treatin& it as such! Thus- when encounterin& int :SL(K; = GE- the preprocessor made no replacements and the code compiled as written! To introduce the I Bacro trick- let's consider a common pro&rammin& pro#lem and see how we should &o a#out solvin& it! Suppose that we want to write a function that- &iven as an ar&ument an enumerated typereturns the strin& representation of the enumerated value! 8or e)ample- &iven the enum
enum 5olor {Ied, Green, Plue, 5%an, :agenta, Sello'#;

0e want to write a function called 5olor;o6tring that returns a strin& representation of the color! 8or e)ample- passin& in the constant Ied should hand #ack the strin& /Ied/- Plue should yield /Plue/- etc! Since the names of enumerated types are lost durin& compilation- we would normally implement this function usin& code similar to the followin&=
string 5olor;o6tring(5olor *) { s'it*h(*) { *ase Ied4 return /Ied/; *ase Plue4 return /Plue/; *ase Green4 return /Green/; *ase 5%an4 return /5%an/; *ase :agenta4 return /:agenta/; *ase Sello'4 return /Sello'/; default4 return / unBno'n)/; # #

"ow- suppose that we want to write a function that- &iven a color- returns the opposite color! P 0e'd need another function- like this one=

P 8or the purposes of this e)ample- we'll work with additive colors! Thus red is the opposite of cyan- yellow is the opposite of #lue- etc!

Chapter 7& -ulti"File Programs, Abstraction, and the Preprocessor


5olor Get=$$osite5olor(5olor *) { s'it*h(*) { *ase Ied4 return 5%an; *ase Plue4 return Sello'; *ase Green4 return :agenta; *ase 5%an4 return Ied; *ase :agenta4 return Green; *ase Sello'4 return Plue; default4 return *; "" @nBno'n *olor, undefined result # #

1 D1 1

These two functions will work correctly- and there's nothin& functionally wron& with them as written! The pro#lem- thou&h- is that these functions are not scalable! 'f we want to introduce new colors- say- 2hite and Pla*B- we'd need to chan&e #oth 5olor;o6tring and Get=$$osite5olor to incorporate these new colors! 'f we accidentally for&et to chan&e one of the functions- the compiler will &ive no warnin& that somethin& is missin& and we will only notice pro#lems durin& de#u&&in&! The pro#lem is that a color encapsulates more information than can #e e)pressed in an enumerated type! Colors also have names and opposites- #ut the C++ enum 5olor knows only a uni5ue '2 for each color and relies on correct implementations of 5olor;o6tring and Get=$$osite5olor for the other two! Somehow- we'd like to #e a#le to &roup all of this information into one place! 0hile we mi&ht #e a#le to accomplish this usin& a set of C++ stru*t constants Ke!&! definin& a color stru*t and makin& *onst instances of these stru*ts for each colorL- this approach can #e #ulky and tedious! 'nstead- we'll choose a different approach #y usin& I Bacros! The idea #ehind I Bacros is that we can store all of the information needed a#ove inside of calls to preprocessor macros! 'n the case of a color- we need to store a color's name and opposite! Thus- let's suppose that we have some macro called 9E&(KEL5=7=I that takes in two parameters correspondin& to the name and opposite color! 0e ne)t create a new file- which we'll call *olor.h- and fill it with calls to this 9E&(KEL5=7=I macro that e)press all of the colors we know Klet's i&nore the fact that we haven't actually defined 9E&(KEL5=7=I yetQ we'll &et there in a momentL! This file looks like this= File& color.h
9E&(KEL5=7=I(Ied, 5%an) 9E&(KEL5=7=I(5%an, Ied) 9E&(KEL5=7=I(Green, :agenta) 9E&(KEL5=7=I(:agenta, Green) 9E&(KEL5=7=I(Plue, Sello') 9E&(KEL5=7=I(Sello', Plue)

Two thin&s a#out this file should *ump out at you! 8irst- we haven't surrounded the file in the traditional .ifndef !!! .endif #oilerplate- so clients can .in*lude this file multiple times! Second- we haven't provided an implementation for 9E&(KEL5=7=I- so if a caller does include this file- it will cause a compile1 time error! 8or now- don't worry a#out these pro#lems ( you'll see why we've structured the file this way in a moment! et's see how we can use the I Bacro trick to rewrite Get=$$osite5olor- which for convenience is reprinted #elow=

1 D; 1

Chapter 7& -ulti"File Programs, Abstraction, and the Preprocessor

5olor Get=$$osite5olor(5olor *) { s'it*h(*) { *ase Ied4 return 5%an; *ase Plue4 return Sello'; *ase Green4 return :agenta; *ase 5%an4 return Ied; *ase :agenta4 return Green; *ase Sello'4 return Plue; default4 return *; "" @nBno'n *olor, undefined result # #

/ere- each one of the *ase la#els in this switch statement is written as somethin& of the form
*ase color4 return opposite;

ookin& #ack at our *olor.h file- notice that each 9E&(KEL5=7=I macro has the form 9E&(KEL5=7=I(color, opposite)! This su&&ests that we could somehow convert each of these 9E&(KEL5=7=I statements into *ase la#els #y craftin& the proper .define! 'n our case- we'd want the .define to make the first parameter the ar&ument of the *ase la#el and the second parameter the return value! 0e can thus write this .define as
.define 9E&(KEL5=7=I(*olor, o$$osite) *ase *olor4 return o$$osite;

Thus- we can rewrite Get=$$osite5olor usin& I Bacros as


5olor Get=$$osite5olor(5olor *) { s'it*h(*) { .define 9E&(KEL5=7=I(*olor, o$$osite) *ase *olor4 return o$$osite; .in*lude /*olor.h/ .undef 9E&(KEL5=7=I default4 return *; "" @nBno'n *olor, undefined result. # #

This is pretty cryptic- so let's walk throu&h it one step at a time! 8irst- let's simulate the preprocessor #y replacin& the line .in*lude /*olor.h/ with the full contents of *olor.h=
5olor Get=$$osite5olor(5olor *) { s'it*h(*) { .define 9E&(KEL5=7=I(*olor, o$$osite) *ase *olor4 return o$$osite; 9E&(KEL5=7=I(Ied, 5%an) 9E&(KEL5=7=I(5%an, Ied) 9E&(KEL5=7=I(Green, :agenta) 9E&(KEL5=7=I(:agenta, Green) 9E&(KEL5=7=I(Plue, Sello') 9E&(KEL5=7=I(Sello', Plue) .undef 9E&(KEL5=7=I default4 return *; "" @nBno'n *olor, undefined result. # #

"ow- we replace each 9E&(KEL5=7=I #y instantiatin& the macro- which yields the followin&=

Chapter 7& -ulti"File Programs, Abstraction, and the Preprocessor


5olor Get=$$osite5olor(5olor *) { s'it*h(*) { *ase Ied4 return 5%an; *ase Plue4 return Sello'; *ase Green4 return :agenta; *ase 5%an4 return Ied; *ase :agenta4 return Green; *ase Sello'4 return Plue; .undef 9E&(KEL5=7=I default4 return *; "" @nBno'n *olor, undefined result. # #

1 D@ 1

8inally- we .undef the 9E&(KEL5=7=I macro- so that the ne)t time we need to provide a definition for 9E&(KEL5=7=I- we don't have to worry a#out conflicts with the e)istin& declaration! Thus- the final code for Get=$$osite5olor- after e)pandin& out the macros- yields
5olor Get=$$osite5olor(5olor *) { s'it*h(*) { *ase Ied4 return 5%an; *ase Plue4 return Sello'; *ase Green4 return :agenta; *ase 5%an4 return Ied; *ase :agenta4 return Green; *ase Sello'4 return Plue; default4 return *; "" @nBno'n *olor, undefined result. # #

0hich is e)actly what we wanted! The fundamental idea underlyin& the I Bacros trick is that all of the information we can possi#ly need a#out a color is contained inside of the file *olor.h! To make that information availa#le to the outside world- we em#ed all of this information into calls to some macro whose name and parameters are known! 0e do not- however- provide an implementation of this macro inside of *olor.h #ecause we cannot anticipate every possi#le use of the information contained in this file! 'nstead- we e)pect that if another part of the code wants to use the information- it will provide its own implementation of the 9E&(KEL5=7=I macro that e)tracts and formats the information! The #asic idiom for accessin& the information from these macros looks like this=
.define macroname(arguments) "3 some use for the arguments 3" .in*lude /filename/ .undef macroname

/ere- the first line defines the mechanism we will use to e)tract the data from the macros! The second includes the file containin& the macros- which supplies the macro the data it needs to operate! The final step clears the macro so that the information is availa#le to other callers! 'f you'll notice- the a#ove techni5ue for implementin& Get=$$osite5olor follows this pattern precisely! 0e can also use the a#ove pattern to rewrite the 5olor;o6tring function! "ote that inside of 5olor;o6tring- while we can i&nore the second parameter to 9E&(KEL5=7=I- the macro we define to e)tract the information still needs to have two parameters! To see how to implement 5olor;o6tringlet's first revisit our ori&inal implementation=

1 DA 1

Chapter 7& -ulti"File Programs, Abstraction, and the Preprocessor

string 5olor;o6tring(5olor *) { s'it*h(*) { *ase Ied4 return /Ied/; *ase Plue4 return /Plue/; *ase Green4 return /Green/; *ase 5%an4 return /5%an/; *ase :agenta4 return /:agenta/; *ase Sello'4 return /Sello'/; default4 return / unBno'n)/; # #

'f you'll notice- each of the *ase la#els is written as


*ase color4 return /color/;

Thus- usin& I Bacros- we can write 5olor;o6tring as


string 5olor;o6tring(5olor *) { s'it*h(*) { "3 5onvert something of the form 9E&(KEL5=7=I(*olor, o$$osite) 3 into something of the form A*ase *olor4 return /*olor/A; 3" .define 9E&(KEL5=7=I(*olor, o$$osite) *ase *olor4 return .*olor; .in*lude /*olor.h/ .undef 9E&(KEL5=7=I default4 return / unBno'n)/; # #

'n this particular implementation of 9E&(KEL5=7=I- we use the strin&izin& operator to convert the *olor parameter into a strin& for the return value! 0e've used the preprocessor to &enerate #oth Get=$$osite5olor and 5olor;o6tringR There is one final step we need to take- and that's to rewrite the initial enum 5olor usin& the I Bacro trick! Gtherwise- if we make any chan&es to *olor.h- perhaps renamin& a color or introducin& new colors- the enum will not reflect these chan&es and mi&ht result in compile1time errors! et's revisit enum 5olor- which is reprinted #elow=
enum 5olor {Ied, Green, Plue, 5%an, :agenta, Sello'#;

0hile in the previous e)amples of 5olor;o6tring and Get=$$osite5olor there was a reasona#ly o#vious mappin& #etween 9E&(KEL5=7=I macros and *ase statements- it is less o#vious how to &enerate this enum usin& the I Bacro trick! /owever- if we rewrite this enum as follows=
enum 5olor { Ied, Green, Plue, 5%an, :agenta, Sello' #;

Chapter 7& -ulti"File Programs, Abstraction, and the Preprocessor

1 D? 1

't should #e sli&htly easier to see how to write this enum in terms of I Bacros! 8or each 9E&(KEL5=7=I macro we provide- we'll simply e)tract the first parameter Kthe color nameL and append a comma! 'n codethis looks like
enum 5olor { .define 9E&(KEL5=7=I(*olor, o$$osite) *olor, "" Kame follo'ed b% *omma .in*lude /*olor.h/ .undef 9E&(KEL5=7=I #;

This- in turn- e)pands out to


enum 5olor { .define 9E&(KEL5=7=I(*olor, o$$osite) *olor, 9E&(KEL5=7=I(Ied, 5%an) 9E&(KEL5=7=I(5%an, Ied) 9E&(KEL5=7=I(Green, :agenta) 9E&(KEL5=7=I(:agenta, Green) 9E&(KEL5=7=I(Plue, Sello') 9E&(KEL5=7=I(Sello', Plue) .undef 9E&(KEL5=7=I #;

0hich in turn #ecomes


enum 5olor { Ied, Green, Plue, 5%an, :agenta, Sello', #;

0hich is e)actly what we want! .ou may have noticed that there is a trailin& comma at after the final color KSello'L- #ut this is not a pro#lem ( it turns out that it's totally le&al C++ code! Anal/sis of t.e F (acro Trick The I Bacro1&enerated functions have several advanta&es over the hand1written versions! 8irst- the I macro trick makes the code considera#ly shorter! 7y relyin& on the preprocessor to perform the necessary e)pansions- we can e)press all of the necessary information for an o#*ect inside of an I Bacro file and only need to write the synta) necessary to perform some task once! Second- and more importantly- this approach means that addin& or removin& 5olor values is simple! 0e simply need to add another 9E&(KEL5=7=I definition to *olor.h and the chan&es will automatically appear in all of the relevant functions! 8inally- if we need to incorporate more information into the 5olor o#*ect- we can store that information in one location and let any callers that need it access it without accidentally leavin& one out! That said- I Bacros are not a perfect techni5ue! The synta) is considera#ly trickier and denser than in the ori&inal implementation- and it's less clear to an outside reader how the code works! Femem#er that reada#le code is *ust as important as correct code- and make sure that you've considered all of your options #efore settlin& on I Bacros! 'f you're ever workin& in a &roup and plan on usin& the I Bacro trick-

1 D6 1

Chapter 7& -ulti"File Programs, Abstraction, and the Preprocessor

#e sure that your other &roup mem#ers are up to speed on the techni5ue and &et their approval #efore usin& it!P (ore to )*+lore A !ractice !roblems ''ve com#ined the 4Bore to J)plore6 and 4Cractice Cro#lems6 sections #ecause many of the topics we didn't cover in &reat detail in this chapter are #est understood #y playin& around with the material! /ere's a samplin& of different preprocessor tricks and techni5ues- mi)ed in with some pro&rammin& puzzles= 1. ist three ma*or differences #etween .define and the *onst keyword for definin& named constants!

2. 3ive an e)ample- #esides preventin& pro#lems from .in*lude1in& the same file twice- where .ifdef and .ifndef mi&ht #e useful! 5+int& 'hat i$ you)re wor*ing on a pro!ect that must run on 'indows, -ac :, 9, and Linu4 and want to use plat$orm"speci$ic $eatures o$ each(6 3. 0rite a re&ular C++ function called :a+ that returns the lar&er of two int values! J)plain why it does not have the same pro#lems as the macro :AR covered earlier in this chapter! 4. 3ive one advanta&e of the macro :AR over the function :a+ you wrote in the previous pro#lem! 5+int& 'hat is the value o$ Max(1.37, 1.24 ( 'hat is the value o$ M!"(1.37, 1.24 (6 . The followin& C++ code is ille&al #ecause the .if directive cannot call functions=
bool (s<ositive(int +) { return + 0; # .if (s<ositive(:SL5=K6;AK;) "" .define result true .else .define result false .endif -- Error o**urs here

3iven your knowled&e of how the preprocessor works- e)plain why this restriction e)ists! !. Compilers rarely inline recursive functions- even if they are e)plicitly marked inline! 0hy do you think this is> $. Bost of the ST al&orithms are inlined! Considerin& the comple)ity of the implementation of a**umulate from the chapter on ST al&orithms- e)plain why this is! 6. Bodify the earlier definition of enum 5olor such that after all of the colors defined in *olor.hthere is a special value- K=;LAL5=7=I- that specifies a none)istent color! 5+int& #o you actually need to change color.h to do this(6

P The I Bacro trick is a special case of a more &eneral techni5ue known as preprocessor metaprogramming 'f you're interested in learnin& more a#out preprocessor metapro&rammin&- consider lookin& into the 7oost Betapro&rammin& i#rary KBC L- a professional C++ packa&e that simplifies common metapro&rammin& tasks!

Chapter 7& -ulti"File Programs, Abstraction, and the Preprocessor

1 DD 1

7. Usin& I Bacros- write a function 6tring;o5olor which takes as a parameter a string and returns the 5olor o#*ect whose name e4actly matches the input strin&! 'f there are no colors with that name- return K=;LAL5=7=I as a sentinel! 8or e)ample- callin& 6tring;o5olor(/Green/) would return the value Green#ut callin& 6tring;o5olor(/green/) or 6tring;o5olor(/=live/) should #oth return K=;LAL5=7=I! 10. Suppose that you want to make sure that the enumerated values you've made for 5olor do not conflict with other enumerated types that mi&ht #e introduced into your pro&ram! Bodify the earlier definition of 9E&(KEL5=7=I used to define enum 5olor so that all of the colors are prefaced with the identifier e5olorL! 8or e)ample- the old value Ied should chan&e to e5olorLIed- the old Plue would #e e5olorLPlue- etc! 2o not chan&e the contents of *olor.h! 5+int& 2se one o$ the preprocessor string"manipulation operators6 11. The .error directive causes a compile1time error if the preprocessor encounters it! This may sound stran&e at first- #ut is an e)cellent way for detectin& pro#lems durin& preprocessin& that mi&ht snow#all into lar&er pro#lems later in the code! 8or e)ample- if code uses compiler1specific features Ksuch as the GpenBC li#raryL- it mi&ht add a check to see that a compiler1specific .define is in place- usin& .error to report an error if it isn't! The synta) for .error is .error message- where message is a messa&e to the user e)plainin& the pro#lem! Bodify *olor.h so that if a caller .in*ludes the file without first .define1in& the 9E&(KEL5=7=I macro- the preprocessor reports an error containin& a messa&e a#out how to use the file!

1 DE 1

Chapter 7& -ulti"File Programs, Abstraction, and the Preprocessor

12. 'f you're up for a challen&e- consider the followin& pro#lem! 7elow is a ta#le summarizin& various units of len&th= Gnit @ame Beter Centimeter Kilometer 8oot 'nch Bile ,stronomical Unit i&ht .ear Cu#it
P

Lmeters A unit 1!0 0!01 1000!0 0!@0AE 0!0;?A 160<!@AA 1!A<6 ) 10 0!??
11

6uffi* m cm km ft in mi ,U ly cu#it

6/stem Betric Betric Betric Jn&lish Jn&lish Jn&lish ,stronomical ,stronomical ,rchaic

<!A61 Z 101?

a) Create a file called units.h that uses the I macro trick to encode the a#ove ta#le as calls to a macro 9E&(KEL@K(;! 8or e)ample- one entry mi&ht #e 9E&(KEL@K(;(:eter, 8.0, m, :etri*)! b) Create an enumerated type- 7ength@nit- which uses the suffi) of the unit- preceded #y e7ength@nitL- as the name for the unit! 8or e)ample- a cu#it is e7ength@nitL*ubit- while a mile would #e e7ength@nitLmi! ,lso define an enumerated value e7ength@nitLEII=I that serves as a sentinel indicatin& that the value is invalid! c) 0rite a function called 6uffi+6tring;o7ength@nit that accepts a string representation of a suffi) and returns the 7ength@nit correspondin& to that strin&! 'f the string does not match the suffi)- return e7ength@nitLEII=I! d) Create a stru*t- 7ength- that stores a double and a 7ength@nit! 0rite a function Iead7ength that prompts the user for a double and a string representin& an amount and a unit suffi) and stores data in a 7ength! 'f the strin& does not correspond to a suffi)- reprompt the user! .ou can modify the code for Get(nteger from the chapter on streams to make an implementation of GetIeal! e) Create a function- Get@nit;%$e- that takes in a 7ength and returns the unit system in which it occurs Kas a stringL *) Create a function- <rint7ength- that prints out a 7ength in the format amount suffix (amount unitnames)! 8or e)ample- if a 7ength stores 10A!; miles- it would print out 80G.Emi (80G.E :iles) /) Create a function- 5onvert;o:eters- which takes in a 7ength and converts it to an e5uivalent len&th in meters! Surprisin&ly- this pro#lem is not particularly lon& ( the main challen&e is the user input- not the unit mana&ementR

P There is no a&reed1upon standard for this unit- so this is an appro)imate avera&e of the various len&ths!

C.a+ter #8 6T= 6eJuence Containers


_________________________________________________________________________________________________________

In :ctober o$ /;<= I observed that a certain algorithm > parallel reduction > was associated with monoids& collections o$ elements with an associative operation That observation led me to believe that it is possible to associate every use$ul algorithm with a mathematical theory and that such association allows $or both widest possible use and meaning$ul ta4onomy As mathematicians learned to li$t theorems into their most general settings, so I wanted to li$t algorithms and data structures ( ,le) Stepanov- inventor of the ST ! NSte0DO The Standard Template i#rary KST L is a pro&rammer's dream! 't offers efficient ways to store- accessmanipulate- and view data and is desi&ned for ma)imum e)tensi#ility! Gnce you've &otten over the initial synta) hurdles- you will 5uickly learn to appreciate the ST 's sheer power and fle)i#ility! To &ive a sense of e)actly where we're &oin&- here are a few 5uick e)amples of code usin& the ST = 0e can create a list of random num#ers- sort it- and print it to the console in $our lines o$ code.
ve*tor int) m%Je*tor(K@:L(K;6); generate(m%Je*tor.begin(), m%Je*tor.end(), rand); sort(m%Je*tor.begin(), m%Je*tor.end()); *o$%(m%Je*tor.begin(), m%Je*tor.end(), ostreamLiterator int)(*out, /,n/));

0e can open a file and print its contents in two lines o$ code.
ifstream in$ut(/m%-file.t+t/); *o$%(istreambufLiterator *har)(in$ut), istreambufLiterator *har)(), ostreambufLiterator *har)(*out));

0e can convert a strin& to upper case in one line o$ code.


transform(s.begin(), s.end(), s.begin(), 44tou$$er);

'f you aren't already impressed #y the possi#ilities this li#rary entails- keep readin&! .ou will not #e disappointed! $;er;iew of t.e 6T= The ST is lo&ically divided into si) pieces- each consistin& of &eneric components that interoperate with the rest of the li#rary= Containers! ,t the heart of the ST are a collection of container classes- standard C++'s analo& to the CS1067HI ,2Ts! 8or e)ample- you can store an associative collection of keyHvalue pairs in an ST ma$- or a &rowin& list of elements in an ST ve*tor! Iterators! Jach ST container e)ports iterators- o#*ects that view and modify ran&es of stored data! 'terators have a common interface- allowin& you to write code that operates on data stored in ar#itrary containers! Algorit.ms! ST al&orithms are functions that operate over ran&es of data specified #y iterators! The scope of the ST al&orithms is sta&&erin& ( there are al&orithms for searchin&- sortin&reorderin&- permutin&- creatin&- and destroyin& sets of data!

1 E0 1

Chapter ?& ,TL ,e@uence Containers Ada+ters! ST adapters are o#*ects which transform an o#*ect from one form into another! 8or e)ample- the stack adapter transforms a re&ular vector or list into a '8G container- while the istreamLiterator transforms a standard C++ stream into an ST iterator! 2unctors! 7ecause so much of the ST relies on user1defined call#ack functions- the ST provides facilities for creatin& and modifyin& functions at runtime! 0e will defer our discussion of functors to much later in this te)t- as they re5uire a fairly nuanced understandin& of C++! Allocators! The ST allows clients of the container classes to customize how memory is allocated and deallocated- either for dia&nostic or performance reasons! 0hile allocators are fascinatin& and certainly worthy of discussion- they are #eyond the scope of this te)t and we will not cover them here!

2ia&rammatically- these pieces are related as follows=

ALGORITHMS

FUNCTORS

ITERATORS

ADAPTERS

ALLOCATORS

CONTAINERS

/ere- the containers rely on the allocators for memory and produce iterators! 'terators can then #e used in con*unction with the al&orithms! 8unctors provide special functions for the al&orithms- and adapters can produce functors- iterators- and containers! 'f this seems a #it confusin& now- don't worry- you'll understand this relationship well #y the time you've finished the ne)t few chapters! 1./ t.e 6T= is @ecessar/ Up until this point- all of the pro&rams you've encountered have declared a fi)ed num#er of varia#les that correspond to a fi)ed num#er of values! 'f you declare an int- you &et a sin&le varia#le #ack! 'f you need to create multiple different ints for some reason- you have to declare each of the varia#les independently! This has its draw#acks! 8or starters- it means that you need to know how e)actly how much data your pro&ram will #e manipulatin& #efore the pro&ram #e&ins runnin&! /ere's a 5uick pro&rammin& challen&e for you= 0rite a pro&ram that reads in three inte&ers from the user- then prints them in sorted order! /ow could you &o a#out writin& a pro&ram to do this> There are two main technical hurdles to overcome! 8irst- how would we store the num#ers the user enters> Second- how do we sort them> 7ecause we know that the user will #e enterin& three distinct values- we could simply store each of them in their own int varia#le! Thus the first step of writin& code for this pro&ram mi&ht look like this=

Chapter ?& ,TL ,e@uence Containers


.in*lude iostream) .in*lude sstream) .in*lude string) using names$a*e std; int Get(nteger(); "" &rom the streams *ha$ter int main() { int val8 = Get(nteger(); int valE = Get(nteger(); int valC = Get(nteger(); # "3 6ort, then $rint out. 3"

1 E1 1

0e now have our three valuesQ how can we sort them> 't turns out that sortin& a list of inte&ers is a classic al&orithms 5uestion and there are many ele&ant solutions to the pro#lem! Some al&orithms like @uic*sort and heapsort run e)tremely 5uickly- #ut are rather difficult to implement! 'nstead- we'll use a variant al&orithm called selection sort! The idea #ehind selection sort is as follows! 'f we want to sort a list of num#ers- we can find the smallest element in the list- then move it to the front of the list! 0e can then find the second1smallest value- then put it in the second position- find the third1smallest and put it in the third position- etc! ,mazin&ly- with *ust the tools we've seen so far this simple al&orithm is e)tremely hard to implement! /ere's some code for the operation=
int main() { int val8 = Get(nteger(); int valE = Get(nteger(); int valC = Get(nteger(); "3 ;hree *ases4 Either val8 is the smallest, valE is the smallest, or 3 valC is the smallest. 2hi*hever ends u$ being the *ase, 'eAll $ut 3 the smallest value into val8. ;his uses the s'a$() fun*tion, 'hi*h is 3 defined in the algorithm) header and sim$l% s'a$s the values of 3 t'o variables. 3" if (valE = val8 ?? valE = valC) "" valE is smallest s'a$ (val8, valE); else if (valC = val8 ?? valC = valE) "" valC is smallest s'a$ (val8, valC); "" =ther'ise, val8 is smallest, and *an remain at the front. "3 Ko', sort valE and valC. 6in*e thereAs >ust t'o elements, 'e *an do a 3 sim$le *om$arison to determine 'hi*h is the smaller of the t'o. 3" if (valC = valE) "" valC is smaller s'a$ (valE, valC); "" =ther'ise, valE is smallest and 'e donAt need to do an%thing. # *out val8 A A valE A A valC endl;

This code is incredi#ly dense! 2on't panic if you don't understand it ( part of the purpose of this e)ample is to illustrate how difficult it can #e to write &ood code for this pro#lem without the ST R 7ut of course- there's another ma*or pro#lem with this code! et's modify the pro#lem statement a #it #y allowin& the user to enter $our num#ers! 'f we make this chan&e- usin& *ust the techni5ues we've covered so far we'll #e forced to write code alon& the followin& lines=

1 E; 1
int main() { int val8 int valE int valC int valG = = = = Get(nteger(); Get(nteger(); Get(nteger(); Get(nteger();

Chapter ?& ,TL ,e@uence Containers

"3 &ind the smallest. 3" if (valE = val8 ?? valE = valC ?? valE = valG) "" valE is smallest s'a$ (val8, valE); else if (valC = val8 ?? valC = valE ?? valC = valG) "" valC is smallest s'a$ (val8, valC); else if (valG = val8 ?? valG = valE ?? valG = valC) "" valG is smallest s'a$ (val8, valG); "" =ther'ise, val8 is smallest, and *an remain at the front. "3 &ind the se*ond-smallest. 3" if (valC = valE ?? valC = valG) "" valC is smallest s'a$ (valE, valC); else if (valG = valE ?? valG = valC) "" valG is smallest s'a$ (valE, valG); "" =ther'ise, valE is smallest, and *an remain at the front. "3 &ind the third-smallest. 3" if (valG = valC) "" valG is smaller s'a$ (valC, valG); "" =ther'ise, valC is smallest and 'e donAt need to do an%thing. *out # val8 A A valE A A valC A A valG endl;

This code is *ust downri&ht awfulR 't's cryptic- difficult to read- and not the sort of code you'd like to #rin& home to mom and dad! "ow ima&ine what the code would look like if we had $ive num#ers instead of four! 't will keep &rowin& and &rowin&- #ecomin& pro&ressively more impossi#le to read until eventually we'd &ive up in frustration! 0hat's worse- thou&h- is that each of these pro&rams is a special case of a &eneral pro#lem ( read in n inte&ers from the user and print them in sorted order ( #ut the code for each case #ears little to no resem#lance to the code for each other case! Introducing t.e #ector 0hat's missin& from our pro&rammin& repertoire ri&ht now is the a#ility to create and access a variable number of o#*ects! Fi&ht now- if we want to store a se5uence of five inte&ers- we must create five independent inte&er varia#les and have no way of accessin& them uniformly! 8ortunately- the ST provides us a versatile tool called the #ector that allows us to store se5uences of elements usin& a sin&le varia#le! ,s you'll see- the ve*tor is nothin& short of e)traordinary and will arise time and a&ain throu&hout your pro&rammin& career! ,t a hi&h level- a ve*tor is an o#*ect that represents a se5uence of elements! This means that you can use a vector to store a &rocery list- a list of Glympic fi&ure skatin& scores- or a set of files to read! The elements in a ve*tor are inde4ed- meanin& that they have a well1defined position in the se5uence! 8or e)ample&iven the se5uence

Chapter ?& ,TL ,e@uence Containers Talue 'nde)


8CD GE ED8F C8G8 G80

1 E@ 1

The first element K1@DL is at position zero- the second KA;L at position one- etc! "otice that elements in the se5uence appear in the order 0- 1- ;- etc! rather than the more intuitive 1- ;- @- !!! ! .ou have seen this already in your e)ploration of the strin& class- so hopefully this notation isn't too startlin&! The ma*or difference #etween the vector and the strin& is that the ve*tor can #e confi&ured to store elements of any type! That is- you can have a ve*tor of ints- a ve*tor of strings- or even a ve*tor of ve*tors of strings! /owever- while the ve*tor can store elements of any type- any sin&le ve*tor can only store elements of a sin&le type! 't is ille&al to create a ve*tor that stores a se5uence of many different types of elements- meanin& that you can't represent the list 0- ,pple- ;!D1E;E #ecause each of the list elements has a different type! This may seem like a rather ar#itrary restriction ( theoretically speakin&- there's no reason that you shouldn't #e a#le to have lists of all sorts of elements ( #ut fortunately in most cases this restriction does not pose too much of a pro#lem! 7ecause vectors can only store elements of a fi)ed type- when you create a ve*tor in your pro&rams you will need to e)plicitly indicate to the compiler what type of elements you aim to store in the ve*tor! ,s an e)ample- to create a ve*tor of ints- you would write
ve*tor int) m%Je*tor;

/ere- we declare a local varia#le called m%Je*tor that has type ve*tor int)! The type inside of the an&le #rackets is called a template argument and indicates to C++ what type of elements are stored in the ve*tor! /ere- the type is int- #ut it's le&al to put pretty much whatever type you would like in the #rackets! 8or e)ample- all of the followin& declarations are le&al=
ve*tor int) intJe*tor; "" 6tores ints ve*tor string) strJe*tor; "" 6tores strings ve*tor double) realJe*tor; "" 6tores real numbers

't is also perfectly le&al to store your own custom structs in a ve*tor- as seen here=
stru*t :%6tru*t { int m%(nt; double m%9ouble; string m%6tring; #; ve*tor :%6tru*t) m%6tru*tJe*tor; "" 6tores :%6tru*ts

'n order to use the ve*tor type- you will need to .in*lude ve*tor) at the top of your pro&ram! ,s we e)plore some of the other ST containers- this pattern will also apply! 0e now know how to create ve*tors- #ut how do we use them> To &ive you a feel for how the ve*tor works- let's return to our previous e)ample of readin& in num#ers and printin& them out in sorted order! Usin& a ve*tor- this can #e accomplished very ele&antly! 0e'll #e&in #y definin& a constant- BKumJalueswhich will represent the num#er of elements to read in! This is shown here=

1 EA 1
.in*lude iostream) .in*lude ve*tor) "" Ke*essar% to use ve*tor .in*lude string) .in*lude sstream) using names$a*e std;

Chapter ?& ,TL ,e@uence Containers

string Get7ine(); "" As defined in the $revious *ha$ter int Get(nteger(); "" As defined in the $revious *ha$ter *onst int BKumJalues = 80; int main() { "3 ... still more 'orB to *ome ... 3" #

"ow- we'll show to how to read in BKumJalues values from the user and store them inside a ve*tor! 8irst- we'll have to create the ve*tor- as shown here=
int main() { ve*tor int) values; "3 ... 3" #

, freshly1constructed ve*tor- like a freshly1constructed string- is initially empty! Conse5uently- we'll need to &et some values from the user- then store them inside the ve*tor! Feadin& the values is fairly easyQ we simply sit in a for loop readin& data from the user! 7ut how do we store them in the ve*tor> There are several ways to do this- of which the simplest is the $ushLba*B function! The $ushLba*B function can #e invoked on a ve*tor to add a new element to the end of ve*tor's se5uence! 8or e)ample&iven a ve*tor mana&in& the followin& se5uence=

Talue 'nde)

80

Then callin& push[#ack on the vector to store the value fifteen would cause the vector to mana&e the new se5uence

Talue 'nde)

80

8H

Syntactically- $ushLba*B can #e used as follows=


int main() { ve*tor int) values; for (int i = 0; i BKumJalues; !!i) { *out /Enter another value4 /; int val = Get(nteger(); values.$ushLba*B(val); # #

Chapter ?& ,TL ,e@uence Containers

1 E? 1

"otice that we write values.$ushLba*B(val) to append the num#er val to the se5uence stored inside the ve*tor! "ow that we have read in our se5uence of values- let's work on the ne)t part of the pro&ram- sortin& the elements in the vector and printin& them to the user! 8or this we'll still use the selection sort al&orithm- #ut it will #e miraculously easier to follow when implemented on top of the ve*tor! Fecall that the &eneral description of the selection sort al&orithm is as follows= 8ind the smallest element of the list! Cut that element at the front of the list! Fepeat until all elements are in place!

et's see how to implement this function! 0e'll #e&in simply #y writin& out the function si&nature- which looks like this=
void 6ele*tion6ort(ve*tor int)? v) { "3 ... 3" #

This function is named 6ele*tion6ort and takes as a parameter a ve*tor int) #y reference! There are two key points to note here! 8irst- we still have to e)plicitly indicate what type of elements are stored in the ve*tor parameter! That is- it's ille&al to write code of this sort=
void 6ele*tion6ort(ve*tor? v) { "" Error4 "3 ... 3" # 2hat Bind of ve*torT

,s a &eneral rule- you will never see ve*tor unless it's immediately followed with a type in an&le #rackets! The reason is simple ( every ve*tor can only store one type of element- and unless you e)plicitly indicate what that type is the compiler will have no way of knowin&! The other important detail a#out this function is that it takes its parameter #y reference! 0e will #e sortin& the ve*tor in1place- meanin& that we will #e reorderin& the elements of the ve*tor rather than creatin& a new ve*tor containin& a sorted copy of the input! 0e now have the function prototype set up- so let's &et into the meat of the al&orithm! To implement selection sort- we'll need to find the smallest element and put it in front- the the second1smallest element and put it in the second position- etc! The code for this is as follows=
void 6ele*tion6ort(ve*tor int)? v) { for (siUeLt i = 0; i v.siUe(); !!i) { siUeLt smallest(nde+ = Get6mallest(nde+(v, i); "" 2eAll 'rite this "" fun*tion momentaril% s'a$ (v[i], v[smallest(nde+]); # #

This code is fairly dense and introduces some synta) you have not yet seen #efore- so let's take a few moments to walk throu&h e)actly how it works! The first detail that mi&ht have cau&ht your eye is this one=
for (siUeLt i = 0; i v.siUe(); !!i)

1 E6 1

Chapter ?& ,TL ,e@uence Containers

This for loop looks stran&e for two reasons! 8irst- instead of creatin& an int varia#le for the iteration- we create a varia#le of type siUeLt! , siUeLt is a special type of varia#le that can hold values that represent si8es of thin&s KsiUeLt stands for 4size type6L! 'n many aspects siUeLt is like a re&ular int ( it holds an inte&er value- can #e incremented with !!- compared usin& the relational operators- etc! /owever- unlike re&ular ints- siUeLts cannot store ne&ative values! The intuition #ehind this idea is that no collection of elements can have a ne&ative size! .ou may have a list of no elements- or a list of #illions of elements- #ut you'll never encounter a list with 11 elements in it! Conse5uently- when iteratin& over an ST container- it is customary to use the special type siUeLt to e)plicitly indicate that your iteration varia#le should always #e nonne&ative! The other detail of this for loop is that the loop iterates from 0 to v.siUe()! The siUe() mem#er function on the ST ve*tor returns the num#er of elements stored in the se5uence- *ust like the siUe() and length() functions on the standard string class! 'n this particular case we could have iterated from 0 to BKumJalues- since we're &uaranteed that the main function will produce a ve*tor of that many elements- #ut in &eneral when iteratin& over a vector it's pro#a#ly a wise idea to use the ve*tor's size as an upper #ound so that the code works for vectors of ar#itrarily many elements! et's continue onward throu&h the code! The #ody of the loop is this code here=
siUeLt smallest(nde+ = Get6mallest(nde+(v, i); s'a$ (v[i], v[smallest(nde+]);

This calls some function called Get6mallest(nde+ Kwhich we have not yet definedL which takes in the vector and the current inde)! 0e will implement this function shortly- and its *o# will #e to return the inde) of the smallest element in the vector occurrin& no earlier than position i! 0e then use the s'a$ function to e)chan&e the values stored in at positions i and smallest(nde+ of the ve*tor! "otice that- as with the standard strin& class- the synta) v[i] means 4the element in ve*tor v at position i!6 et's take a minute to think a#out how this code works! The varia#le i counts up from 0 to v.siUe() - 8 and visits every element of the ve*tor e)actly once! Gn each iteration- the code finds the smallest element in the ve*tor occurrin& no earlier than position i- then e)chan&es it with the element at position i! This means that the code will 1. 8ind the smallest element of the ve*tor and put it in position 0! 2. 8ind the smallest element of the remainder of the ve*tor and put it in position 1! 3. 8ind the smallest element of the remainder of the ve*tor and put it in position ;! !!! This is precisely what we set out to do- and so the code will work marvelously! Gf course- this assumes that we have a function called Get6mallest(nde+ which returns the inde) of the smallest element in the ve*tor occurrin& no earlier than position i! To finalize our implementation of 6ele*tion6ort- let's &o implement this function! ,&ain- we'll start with the prototype- which is shown here=
siUeLt Get6mallest(nde+(ve*tor int)? v, siUeLt start(nde+) { "3 ... 3" #

This function accepts as input a ve*tor int) #y reference and a siUeLt containin& the start inde)- then returns a siUeLt containin& the result! There's an important #ut su#tle detail to note here! ,t a hi&h level- the Get6mallest(nde+ function has no #usiness modifyin& the ve*tor it takes as input! 'ts task is to find the smallest element and return it- no more! So why e)actly does this function take the ve*tor int) parameter #y reference> The answer is e$$iciency! 'n C++- if you pass a parameter to a function #y value- then whenever that function is called C++ will make a full copy of the ar&ument! 0hen workin& with the ST containers- which can contain thousands Kif not millions or tens of millionsL of elements- the cost of copyin& the container can #e sta&&erin&! Conse5uently- it is considered &ood

Chapter ?& ,TL ,e@uence Containers

1 ED 1

pro&rammin& practice to pass ST containers into functions #y reference rather than #y value- since this avoids an e)pensive copy!P The implementation of this function is rather strai&htforward=
siUeLt Get6mallest(nde+(ve*tor int)? v, siUeLt start(nde+) { siUeLt best(nde+ = start(nde+; for (siUeLt i = start(nde+; i if (v[i] v[best(nde+]) best(nde+ = i; return best(nde+; # v.siUe(); !!i)

This function iterates over the elements of the ve*tor startin& with position i- checkin& whether the element at the current position is less than the smallest element we've seen so far! 'f so- the function updates where in the ve*tor that element appears! ,t the end of the function- once we've looked at every element in ran&e- the best(nde+ varia#le will hold the inde) of the smallest element in ve*tor v occurrin& no earlier than start(nde+- and so we return the value! 0e've implemented the Get6mallest(nde+ function- meanin& that we have a workin& implementation of 6ele*tion6ort! To finalize our pro&ram- let's update the main function to print out the sorted vector! This is shown here=
int main() { ve*tor int) values; for (int i = 0; i BKumJalues; !!i) { *out /Enter another value4 /; int val = Get(nteger(); values.$ushLba*B(val); # 6ele*tion6ort(values); for (siUeLt i = 0; i *out values[i] BKumJalues; !!i) endl;

Compare this implementation of the pro&ram to the previous version- which did not have the lu)ury of usin& ve*tor! ,s you can see- the code in this pro&ram is si&nificantly clearer than #efore! Boreover- it's much more scalable! 'f we want to read in a different num#er of values from the user- we can do so simply #y ad*ustin& the value of the BKumJalues constant- and the rest of the code will update automatically! An Alternati;e Im+lementation 'n the previous section- we wrote a pro&ram which reads in some num#er of values from the user- sorts them- and then prints them out! Gf course- the pro&ram we wrote was *ust one method for solvin& the pro#lem! 'n particular- there is another implementation strate&y we could have considered that lends itself to a su#stantially shorter implementation! "otice that in the a#ove pro&ram- we read in a list of values from the user and #lindly added them to the end of the list we wanted to sort! These values weren't necessarily in sorted order- and so we had to run a postprocessin& step to sort the vector #efore displayin&
P 'n practice you would almost certainly pass the parameter #y re$erence"to"const- which indicates that the parameter cannot #e modified! 0e will take this issue up in a later chapter- #ut for now pass1#y1reference should #e &ood enou&h for our purposes!

1 EE 1

Chapter ?& ,TL ,e@uence Containers

it to the user! 7ut what if we opt for a different approach> 'n particular- suppose that whenever we read a value from the user- instead of puttin& that value at the end of the se5uence- we find where in the vector the element should &o- then insert the value at that point> 8or e)ample- suppose that the user has entered the followin& four values=

Talue 'nde)

800

E00

C00

G00

"ow suppose that she enters the num#er 1@D! 'f we append 1@D to the ve*tor- then the num#ers will not all #e in sorted order! 'nstead- we'll find the location where 1@D should &o in the sorted ve*tor- then insert it directly into that location! This is shown here=

Talue 'nde)

800

8CD

E00

C00

G00

This strate&y ends up #ein& a #it simpler to implement than our previous pro&ram- which relied on selection sort! Gf course- to implement the pro&ram usin& the a#ove strate&y- we need to answer two 5uestions! 8irst- how do we find out where in the ve*tor the user's element should &o> Second- how do we insert an element into a ve*tor directly at that position> This first 5uestion is al&orithmicQ the second is simply a 5uestion of what operations are le&al on the ve*tor! Conse5uently- we'll #e&in our discussion with how to find the insertion point- and will then see how to add an element to a ve*tor at a particular point! Suppose that we are &iven a sorted list of inte&ers and some value to insert into the list! 0e are curious to find at what inde) the new value should &o! This is an interestin& al&orithmic challen&e- since there are many valid solutions! /owever- there's one particular simple way to find where the element should &o! 'n order for a list to #e in sorted order- every element has to #e smaller than the element that comes one position after it! Therefore- if we find the first element in the ve*tor that is bigger than the element we want to insert- we know that the element we want to insert must come directly #efore that element! This su&&ests the followin& al&orithm=
"3 $atch out! %his code contains a bug! 3" siUeLt (nsertion(nde+(ve*tor int)? v, int to(nsert) { for(siUeLt i = 0; i v.siUe(); !!i) if (to(nsert v[i]) return i; #

This code is mostly correct- #ut contains a pretty si&nificant flaw! 'n particular- what happens if the element we want to insert is #i&&er than every element in the ve*tor> 'n that case- the if statement inside of the for loop will never evaluate to true- and so the function will not return a value! 'f a function finishes without returnin& a value- the pro&ram has unde$ined behavior! This means that the function mi&ht return zero- it mi&ht return &ar#a&e- or your pro&ram mi&ht immediately crash outri&ht! This certainly isn't what we want to have happen- so how can we &o a#out fi)in& it> "otice that the only way that the a#ove function never returns a value is if the element to #e inserted is at least as #i& as every element in the ve*tor! 'n that case- the correct #ehavior should #e to put the element on the end of the ve*tor! 0e'll si&nal this #y havin& the function return v.siUe() if the element is #i&&er than every element in the se5uence! This is shown here=

Chapter ?& ,TL ,e@uence Containers


siUeLt (nsertion(nde+(ve*tor int)? v, int to(nsert) { for(siUeLt i = 0; i v.siUe(); !!i) if (to(nsert v[i]) return i; return v.siUe(); #

1 E< 1

,ll that's left to do now is use this function to #uild a sleek implementation of the pro&ram! 7ut #efore we can do that- we have to see how to insert an element into a ve*tor at an ar#itrary position! The &ood news is that the ve*tor supports this operation naturally- and in fact you can insert an element into a ve*tor at any position! The #ad news is that the synta) for doin& so is nothin& short of cryptic and without an understandin& of ST iterators will look entirely alien! 0e'll talk a#out iterators more ne)t chapter- #ut in the meantime you can *ust take it for &ranted that the followin& synta) is le&al! 3iven a ve*tor v and an element e- to insert e into v at position n- we use the synta)
v.insert(v.begin() ! n, e);

8or e)ample- to insert the element 1@D at position zero in the vector- you would write
v.insert(v.begin(), 8CD);

Similarly- to insert the element A; at position five- we could write


v.insert(v.begin() ! H, GE);

Gne of the trickier parts of the insert function is determinin& e)actly where the element will #e inserted! Fecall that ve*tors are zero1inde)ed- the a#ove statement will insert the num#er A; as the si4th element of the se5uence- not the fifth! 0hen an element is inserted at a position- all of the elements after it are shuffled down one spot to make room- so callin& insert will never overwrite a value! 3iven this synta) and the a#ove implementation of (nsertion(nde+- we can write a pro&ram to read in a list of values and print them out in sorted order as follows=
int main() { ve*tor int) values; "3 Iead the values. 3" for (int i = 0; i BKumJalues; !!i) { *out /Enter an integer4 /; int val = Get(nteger(); "3 (nsert the element at the *orre*t $osition. 3" values.insert(values.begin() ! (nsertion(nde+(values, val), val); # "3 <rint out the sorted list. 3" for (siUeLt i = 0; i values.siUe(); !!i) *out values[i] endl;

This code is much shorter than #efore- even when you factor in the code for (nsertion(nde+!

1 <0 1 Additional #ector $+erations

Chapter ?& ,TL ,e@uence Containers

The previous section on sortin& num#ers with the ve*tor showcased many of operations that can #e performed on a ve*tor- #ut was #y no means a complete survey of what the ve*tor can do! 0hile some ve*tor operations re5uire a nuanced understandin& of iterators- which we will cover ne)t chapter- there are a few common operations on the ve*tor that we will address in this section #efore movin& on to other container classes! Gne of the key distinctions #etween the ve*tor and other data types we've seen so far is that the ve*tor has a varia#le size! 't can contain no elements- dozens of elements- or even millions of elements! 'n the precedin& e)amples- we e)plored two ways to chan&e the num#er of elements in the ve*tor= $ushLba*Bwhich appends new elements to the #ack of the ve*tor- and insert- which adds an element to the ve*tor at an ar#itrary position! /owever- there are several more ways to add and remove elements from the ve*tor- some of which are discussed here! 0hen creatin& a new vector to represent a list of values- #y default C++ will make the ve*tor store an empty list! That is- a newly1created ve*tor is #y default empty! /owever- at times you mi&ht want to initialize the ve*tor to a certain size! C++ allows you to do this #y specifyin& the startin& size of the ve*tor at the point where the vector is created! 8or e)ample- to create a ve*tor of inte&ers that initially holds fifteen elements- you could write this as
ve*tor int) m%Je*tor(8H);

That is- you declare the ve*tor as normal- and put the default size in parentheses afterwards! "ote that this only chan&es the startin& size of the ve*tor- and you are free to add additional elements to the ve*tor later in your pro&ram! 0hen creatin& a ve*tor that holds primitive types- such as int or double- the elements in the ve*tor will default to zero Kor false in the case of boolsL! This means that the a#ove line of code means 4create a ve*tor of inte&ers called m%Je*tor that initially holds fifteen entries- all zero!6 Similarly- this line of code=
ve*tor string) m%6tringJe*tor(80);

0ill create a ve*tor of strings that initially holds ten copies of the empty strin&! 'n some cases- you may want to initialize the ve*tor to a certain size where each element holds a value other than zero! .ou may wish- for e)ample- to construct a ve*tor string) holdin& five copies of the strin& 4(none)-6 or a ve*tor double) holdin& twenty copies of the value 1@D! 'n these cases- C++ lets you specify #oth the num#er and default value for the elements in the vector usin& the followin& synta)=
ve*tor double) m%Ieals(E0, 8CD.0); ve*tor string) m%6trings(H, /(none)/);

"otice that we've enclosed in parentheses #oth the number of startin& elements in the vector and the value of these startin& elements! ,n important detail is that this synta) is only le&al when initially creatin& a ve*tor! 'f you have an e)istin& ve*tor and try to use this synta)- you will &et a compile1time error! That is- the followin& code is ille&al=
ve*tor double) m%Ieals; m%Ieals(E0, 8CD.0); "" Error4 =nl% legal to do this 'hen the ob>e*t is *reated

Chapter ?& ,TL ,e@uence Containers

1 <1 1

'f you want to chan&e the num#er of elements in a ve*tor after it has already #een created- you can always use the $ushLba*B and insert mem#er functions! /owever- if you'd like to make an a#rupt chan&e in the num#er of elements in the ve*tor Kperhaps #y addin& or deletin& a lar&e num#er of elements all at onceL- you can use the ve*tor's resiUe mem#er function! The resiUe function is very similar to the synta) we've *ust encountered= you can specify either a num#er of elements or a num#er of elements and a value- and the ve*tor will #e resized to hold that many elements! /owever- resiUe #ehaves somewhat differently from the previous construct #ecause when usin& resiUe- the ve*tor mi&ht already contain elements! Conse5uently- resiUe works #y addin& or removin& elements from the end of the ve*tor until the desired size is reached! To &et a #etter feel for how resiUe works- let's suppose that we have a function called <rintJe*tor that looks like this=
void <rintJe*tor(ve*tor int)? elems) { for (siUeLt i = 0; i elems.siUe(); !!i) *out elems[i] A A; *out endl; #

This function takes in a ve*tor int)- then prints out the elements in the ve*tor one at a time- followed #y a newline! 3iven this function- consider the followin& code snippet=
ve*tor int) m%Je*tor; <rintJe*tor(m%Je*tor); m%Je*tor.resiUe(80); <rintJe*tor(m%Je*tor); m%Je*tor.resiUe(H); <rintJe*tor(m%Je*tor); m%Je*tor.resiUe(D, 8); <rintJe*tor(m%Je*tor); m%Je*tor.resiUe(8, D); <rintJe*tor(m%Je*tor); "" 9efaults to em$t% ve*tor "" =ut$ut4 [nothing] "" Gro' the ve*tor, setting ne' elements to 0 "" =ut$ut4 0 0 0 0 0 0 0 0 0 0 "" 6hrinB the ve*tor "" =ut$ut4 0 0 0 0 0 "" Gro' the ve*tor, setting ne' elements to 8 "" =ut$ut4 0 0 0 0 0 8 8 "" ;he se*ond $arameter is effe*tivel% ignored. "" =ut$ut4 0

'n the first line- we construct a new ve*tor- which is #y default empty! Conse5uently- the call to <rintJe*tor will produce no output! 0e then invoke resiUe to add ten elements to the ve*tor! These elements are added to the end of the ve*tor- and #ecause we did not specify a default value are all initialized to zero! Gn our ne)t call to resiUe- we shrink the ve*tor down to five elements! "e)t- we use resiUe to e)pand the vector to hold seven elements! 7ecause we specified a default value- the newly1 created elements default to 1- and so the se5uence is now 0- 0- 0- 0- 0- 1- 1! 8inally- we use resiUe to trim the se5uence! 7ecause the second ar&ument to resiUe is only considered if new elements are added- it is effectively i&nored! 0e've seen several vector operations so far- #ut there is a wide class of operations we have not yet considered ( operations which remove elements from the ve*tor! ,s you saw- the $ushLba*B and insert functions can #e used to splice new elements into the ve*tor's se5uence! These two functions are #alanced #y the $o$Lba*B and erase functions! $o$Lba*B is the opposite of $ushLba*B- and removes the last element from the vector's se5uence! erase is the deletion counterpart to insert- and removes an element at a particular position from the ve*tor! ,s with insert- the synta) for erase is a #it tricky! To remove a sin&le element from a random point in a ve*tor- use the erase method as follows=
m%Je*tor.erase(m%Je*tor.begin() ! n);

1 <; 1 where n represents the inde) of the element to erase!

Chapter ?& ,TL ,e@uence Containers

'n some cases- you may feel compelled to completely erase the contents of the ve*tor! 'n that case- you can use the *lear function- which completely erases the ve*tor contents! *lear can #e invoked as follows=
m%Je*tor.*lear();

6ummar/ of #ector The followin& ta#le lists some of the more common operations that you can perform on a ve*tor! 0e have not talked a#out iterators or the *onst keyword yet- so don't worry if you're confused #y those terms! This ta#le is desi&ned as a reference for any point in your pro&rammin& career- so feel free to skip over entries that look too intimidatin&!
Constructor= ve*tor
;) () ve*tor int) m%Je*tor;

Constructs an empty vector! Constructor= ve*tor


;) (siUeLt%$e siUe) ve*tor int) m%Je*tor(80);

Constructs a vector of the specified size where all elements use their default values Kfor inte&ral types- this is zeroL! Constructor=
ve*tor ;) (siUeLt%$e siUe, *onst ;? default) ve*tor string) m%Je*tor(H, /blanB/);

Constructs a vector of the specified size where each element is e5ual to the specified default value!
for(int i = 0; i m%Je*tor.siUe(); !!i) { ... #

siUeLt%$e siUe() *onst;

Feturns the num#er of elements in the vector!


bool em$t%() *onst; 'hile(1m%Je*tor.em$t%()) { ... #

Feturns whether the vector is empty!


void *lear(); m%Je*tor.*lear();

Jrases all the elements in the vector and sets the size to zero!
;? o$erator [] (siUeLt%$e $osition); *onst ;? o$erator [] (siUeLt%$e $osition) *onst; ;? at(siUeLt%$e $osition); *onst ;? at(siUeLt%$e $osition) *onst; m%Je*tor[0] = 800; int + = m%Je*tor[0]; m%Je*tor.at(0) = 800; int + = m%Je*tor.at(0);

Feturns a reference to the element at the specified position! The #racket notation NO does not do any #ounds checkin& and has undefined #ehavior past the end of the data! The at mem#er function will throw an e)ception if you try to access data #eyond the end! 0e will cover e)ception handlin& in a later chapter!

Chapter ?& ,TL ,e@uence Containers


void resiUe(siUeLt%$e ne'6iUe); void resiUe(siUeLt%$e ne'6iUe, ; fill); m%Je*tor.resiUe(80); m%Je*tor.resiUe(80, /default/);

1 <@ 1

Fesizes the vector so that it's &uaranteed to #e the specified size! 'n the second version- the ve*tor elements are initialized to the value specified #y the second parameter! Jlements are added to and removed from the end of the vector- so you can't use resiUe to add elements to or remove elements from the start of the vector!
void $ushLba*B(); m%Je*tor.$ushLba*B(800);

,ppends an element to the ve*tor!


;? ba*B(); *onst ;? ba*B() *onst; m%Je*tor.ba*B() = H; int lastElem = m%Je*tor.ba*B();

Feturns a reference to the last element in the ve*tor!


;? front(); *onst ;? front() *onst; m%Je*tor.front() = 0; int firstElem = m%Je*tor.front();

Feturns a reference to the first element in the vector!


void $o$Lba*B(); m%Je*tor.$o$Lba*B();

Femoves the last element from the vector!


iterator begin(); *onstLiterator begin() *onst; ve*tor int)44iterator itr = m%Je*tor.begin();

Feturns an iterator that points to the first element in the vector!


iterator end(); *onstLiterator end() *onst; 'hile(itr 1= m%Je*tor.end());

Feturns an iterator to the element a$ter the last! The iterator returned #y end does not point to an element in the vector!
iterator insert(iterator $osition, *onst ;? value); void insert(iterator start, siUeLt%$e num5o$ies, *onst ;? value); m%Je*tor.insert(m%Je*tor.begin() ! G, /0ello/); m%Je*tor.insert(m%Je*tor.begin(), E, /So1/);

The first version inserts the specified value into the vectorand the second inserts num5o$ies copies of the value into the vector! 7oth calls invalidate all outstandin& iterators for the vector!
m%Je*tor.erase(m%Je*tor.begin()); m%Je*tor.erase(start(tr, end(tr);

iterator erase(iterator $osition); iterator erase(iterator start, iterator end);

The first version erases the element at the position pointed to #y position! The second version erases all elements in the ran&e Nstart(tr- end(trL! "ote that this does not erase the element pointed to #y end(tr! ,ll iterators after the remove point are invalidated! 'f usin& this mem#er function on a de[ue Ksee #elowL- all iterators are invalidated! de&ue8 A @ew Cind of 6eJuence

8or most applications where you need to represent a se5uence of elements- the ve*tor is an ideal tool! 't is fast- li&htwei&ht- and intuitive! /owever- there are several aspects of the vector that can #e trou#lesome in certain applications! 'n particular- the ve*tor is only desi&ned to &row in one directionQ callin&

1 <A 1

Chapter ?& ,TL ,e@uence Containers

$ushLba*B inserts elements at the end of the vector- and resiUe always appends elements to the end! 0hile it's possi#le to insert elements into other positions of the ve*tor usin& the insert function- doin&

so is fairly inefficient and relyin& on this functionality can cause a marked slowdown in your pro&ram's performance! 8or most applications- this is not a pro#lem- #ut in some situations you will need to mana&e a list of elements that will &row and shrink on #oth ends! 2oin& this with a ve*tor would #e prohi#itively costly- and we will need to introduce a new container class= the de[ue!
de[ue is a stran&e entity! 't is pronounced 4deck-6 as in a deck of cards- and is named as a contraction of 4dou#le1ended Jueue!6 't is similar to the ve*tor in almost every way- #ut supports a few operations that the ve*tor has trou#le with! 7ecause of its similarity to ve*tor- many C++ pro&rammers don't even know that the de[ue e)ists! 'n fact- of all of the standard ST containers- de[ue is pro#a#ly the least1used! 7ut this is not to say that it is not useful! The de[ue packs si&nificant firepower- and in this ne)t section

we'll see some of the #asic operations that you can perform on it!

0hat's interestin& a#out the de[ue is that all operations supported #y ve*tor are also provided #y de[ue! Thus we can resiUe a de[ue- use the #racket synta) to access individual elements- and erase elements at ar#itrary positions! 'n fact- we can rewrite the num#er1sortin& pro&ram to use a de[ue simply #y replacin& all instances of vector with de[ue! 8or e)ample=
int main() { de[ue int) values; "" @se de[ue instead of ve*tor "3 Iead the values. 3" for (int i = 0; i BKumJalues; !!i) { *out /Enter an integer4 /; int val = Get(nteger(); "3 (nsert the element at the *orre*t $osition. 3" values.insert(values.begin() ! (nsertion(nde+(values, val), val); # "3 <rint out the sorted list. 3" for (siUeLt i = 0; i values.siUe(); !!i) *out values[i] endl;

/owever- de[ues also support two more functions- $ushLfront and $o$Lfront- which work like the ve*tor's $ushLba*B and $o$Lba*B e)cept that they insert and remove elements at the front of the de[ue! 7ut this raises an interestin& 5uestion= if de[ue has strictly more functionality than ve*tor- why use ve*tor> The main reason is speed! de[ues and ve*tors are implemented in two different ways! Typically- a ve*tor stores its elements in conti&uous memory addresses! de[ues- on the other handmaintain a list of different 4pa&es6 that store information! This is shown here=

Chapter ?& ,TL ,e@uence Containers

1 <? 1

#ector

de&ue

These different implementations impact the efficiency of the ve*tor and de[ue operations! 'n a ve*tor#ecause all elements are stored in consecutive locations- it is possi#le to locate elements throu&h simple arithmetic= to look up the nth element of a ve*tor- find the address of the first element in the vector- then *ump forward n positions! 'n a de[ue this lookup is more comple)= the de[ue has to fi&ure out which pa&e the element will #e stored in- then has to search that pa&e for the proper item! /owever- insertin& elements at the front of a ve*tor re5uires the ve*tor to shuffle all e)istin& elements down to make room for the new element KslowL- while doin& the same in the de[ue only re5uires the de[ue to rearran&e elements in a sin&le pa&e KfastL! 'f you're de#atin& a#out whether to use a ve*tor or a de[ue in a particular application- you mi&ht appreciate this advice from the C++ 'SG Standard Ksection ;@!1!1!;L=
#ector is the type o$ se@uence that should be used by de$ault

choice when most insertions and deletions ta*e place at the beginning or at the end o$ the se@uence

de$ue is the data structure o$

'f you ever find yourself a#out to use a vector- check to see what you're doin& with it! 'f you need to optimize for fast access- keep usin& a ve*tor! 'f you're &oin& to #e insertin& or deletin& elements at the #e&innin& or end of the container fre5uently- consider usin& a de[ue instead! )*tended )*am+le8 6nake 8ew computer &ames can #oast the lon&evity or addictive power of ,na*e! Fe&ardless of your #ack&roundchances are that you have played Snake or one of its many variants! The rules are simple ( you control a snake on a two1dimensional &rid and try to eat food pellets scattered around the &rid! .ou lose if you crash into the walls or into your own #ody! True to "ewton's laws- the snake continues movin& in a sin&le direction until you e)plicitly chan&e its #earin& #y ninety de&rees! Jvery time the snake eats food- a new piece of food is randomly placed on the &rid and the snake's len&th increases! Gver time- the snake's #ody &rows so lon& that it #ecomes an o#stacle- and if the snake collides with itself the player loses! /ere's a screenshot from M7asic Aibbles- a Bicrosoft implementation of Snake released with BS12GS version ?!0! The snake is the lon& yellow strin&- and the num#er E is the food=

1 <6 1

Chapter ?& ,TL ,e@uence Containers

7ecause the rules of Snake are so simple- it's possi#le to implement the entire &ame in only a few hundred lines of C++ code! 'n this e)tended e)ample- we'll write a Snake pro&ram in which the computer controls the snake accordin& to a simple ,'! 'n the process- we'll &ain e)perience with the ST ve*tor and de[uethe streams li#rary- and a sprinklin& of C li#rary functions! Gnce we've finished- we'll have a rather snazzy pro&ram that can serve as a launchin& point for further C++ e)ploration! $ur Kersion of 6nake There are many variants of Snake- so to avoid confusion we'll e)plicitly spell out the rules of the &ame we're implementin&= 1. 2. 3. 4. The snake moves #y e)tendin& its head in the direction it's movin& and pullin& its tail in one space! The snake wins if it eats twenty pieces of food! The snake loses if it crashes into itself or into a wall! 'f the snake eats a piece of food- its len&th &rows #y one and a new piece of food is randomly placed! . There is only one level- the startin& level!

0hile traditionally Snake is played #y a human- our Snake will #e computer1controlled so that we can e)plore some important pieces of the C runtime li#rary! 0e'll discuss the ,' we'll use when we #e&in implementin& it! 4e+resenting t.e 1orld 'n order to represent the Snake world- we need to keep track of the followin& information=

Chapter ?& ,TL ,e@uence Containers 1. The size and layout of the world! 2. The location of the snake! 3. /ow many pieces of food we've consumed!

1 <D 1

et's consider this information one piece at a time! 8irst- how should we represent the world> The world is two1dimensional- #ut all of the ST containers we've seen so far only represent lists- which are inherently one1dimensional! Unfortunately- the ST doesn't have a container class that encapsulates a multidimensional array- #ut we can emulate this functionality with an ST ve*tor of ve*tors! 8or e)ample- if we represent each s5uare with an o#*ect of type 2orld;ile- we could use a ve*tor ve*tor 2orld;ile) )! "ote that there is a space #etween the two closin& an&le #rackets ( this is deli#erate and is an unfortunate #u& in the C++ specification! 'f we omit the space- C++ would interpret the closin& #races on ve*tor ve*tor 2orld;ile)) as the stream e)traction operator ))- as in *in )) m%Jalue! ,lthou&h most compilers will accept code that uses two ad*acent closin& #races- it's #ad practice to write it this way! 0hile we could use a ve*tor ve*tor 2orld;ile) )- there's actually a simpler option! Since we need to #e a#le to display the world to the user- we can instead store the world as a ve*tor string) where each strin& encodes one row of the #oard! This also simplifies displayin& the worldQ &iven a ve*tor string) representin& all the world information- we can draw the #oard #y outputtin& each strin& on its own line! Boreover- since we can use the #racket operator NO on #oth ve*tor and string- we can use the familiar synta) 'orld[ro'][*ol] to select individual locations! The first #rackets select the string out of the ve*tor and the second the character out of the string! 0e'll use the followin& characters to encode &ame information= , space character KA AL represents an empty tile! , pound si&n KA.AL represents a wall! , dollar si&n KAYAL represents food! ,n asterisk KA3AL represents a tile occupied #y a snake!

8or simplicity- we'll #undle all the &ame data into a sin&le struct called game;! This will allow us to pass all the &ame information to functions as a sin&le parameter! 7ased on the a#ove information- we can #e&in writin& this struct as follows=
stru*t game; { ve*tor string) 'orld; #;

0e also will need 5uick access to the dimensions of the playin& field- since we will need to #e a#le to check whether the snake is out of #ounds! 0hile we could access this information #y checkin& the dimensions of the ve*tor and the strin&s stored in it- for simplicity we'll store this information e)plicitly in the game; struct- as shown here=
stru*t game; { ve*tor string) 'orld; int numIo's, num5ols; #;

8or consistency- we'll access elements in the ve*tor string) treatin& the first inde) as the row and the second as the column! Thus 'orld[C][H] is row three- column five Kwhere indices are zero1inde)edL!

1 <E 1

Chapter ?& ,TL ,e@uence Containers

"ow- we need to settle on a representation for the snake! The snake lives on a two1dimensional &rid and moves at a certain velocity! 7ecause the &rid is discrete- we can represent the snake as a collection of its points alon& with its velocity vector! 8or e)ample- we can represent the followin& snake=

0 0

"

! "
,s the points K;- 0L- K;- 1L- K;- ;L- K@- ;L- KA- ;L- KA- @L and the velocity vector K11- 0L! The points comprisin& the snake #ody are ordered to determine how the snake moves! 0hen the snake moves- the first point Kthe headL moves one step in the direction of the velocity vector! The second piece then moves into the &ap left #y the first- the third moves into the &ap left #y the second piece- etc! This leaves a &ap where the tail used to #e! 8or e)ample- after movin& one step- the a#ove snake looks like this=

0 0

"

! "
To represent the snake in memory- we thus need to keep track of its velocity and an ordered list of the points comprisin& it! The former can #e represented usin& two ints- one for the \) component and one for the \y component! 7ut how should we represent the latter> 0e've *ust learned a#out the ve*tor and de[ue- each of which could represent the snake! To see what the #est option is- let's think a#out how we mi&ht implement snake motion! 0e can think of snake motion in one of two ways ( first- as the head movin& forward a step and the rest of the points shiftin& down one spot- and second as the snake &ettin& a new point in front of its current head and losin& its tail! The first approach re5uires us to update every element in the #ody and is not particularly efficient! The second approach can easily #e implemented with a de[ue throu&h an appropriate com#ination of $ushLfront and $o$Lba*B! 0e will thus use a de[ue to encode the snake #ody! 'f we want to have a de[ue of points- we'll first need some way of encodin& a point! This can #e done with this struct=

Chapter ?& ,TL ,e@uence Containers


stru*t $oint; { int ro', *ol; #;

1 << 1

Takin& these new considerations into account- our new game; struct looks like this=
stru*t game; { ve*tor string) 'orld; int numIo's, num5ols; de[ue $oint;) snaBe; int d+, d%; #;

8inally- we need to keep track of how many pieces of food we've munched so far! That can easily #e stored in an int- yieldin& this final version of game;=
stru*t game; { ve*tor string) 'orld; int numIo's, num5ols; de[ue $oint;) snaBe; int d+, d%; int numEaten; #;

T.e 6keleton Im+lementation "ow that we've settled on a representation for our &ame- we can start thinkin& a#out how to or&anize the pro&ram! There are two lo&ical steps ( setup and &ameplay ( leadin& to the followin& skeleton implementation=

1 100 1
.in*lude iostream) .in*lude string) .in*lude de[ue) .in*lude ve*tor) using names$a*e std;

Chapter ?& ,TL ,e@uence Containers

"3 Kumber of food $ellets that must be eaten to 'in. 3" *onst int B:a+&ood = E0; "3 5onstants for the different tile t%$es. 3" *onst *har BEm$t%;ile = A A; *onst *har B2all;ile = A.A; *onst *har B&ood;ile = AYA; *onst *har B6naBe;ile = A3A; "3 A stru*t en*oding a $oint in a t'o-dimensional grid. 3" stru*t $oint; { int ro', *ol; #; "3 A stru*t *ontaining relevant game information. 3" stru*t game; { ve*tor string) 'orld; "" ;he $la%ing field int numIo's, num5ols; "" 6iUe of the $la%ing field de[ue $oint;) snaBe; int d+, d%; #; int numEaten; "" ;he snaBe bod% "" ;he snaBe dire*tion "" 0o' mu*h food 'eAve eaten.

"3 ;he main $rogram. (nitialiUes the 'orld, then runs the simulation. 3" int main() { game; game; (nitialiUeGame(game); Iun6imulation(game); return 0; #

,top this pro&ram are the necessary .in*ludes for the functions and o#*ects we're usin&- followed #y a list of constants for the &ame! The $oint; and game; structs are identical to those descri#ed a#ove! main creates a game; o#*ect- passes it into (nitialiUeGame for initialization- and finally hands it to Iun6imulation to play the &ame! 0e'll #e&in #y writin& (nitialiUeGame so that we can &et a valid game; for Iun6imulation! 7ut how should we initialize the &ame #oard> Should we use the same #oard every time- or let the user specify a level of their choosin&> 7oth of these are resaona#le- #ut for the this e)tended e)ample we'll choose the latter! 'n particular- we'll specify a level file format- then let the user specify which file to load at runtime! There are many possi#le file formats to choose from- #ut each must contain at least enou&h information to populate a game; structQ that is- we need the world dimensions and layout- the startin& position of the snake- and the direction of the snake! 0hile ' encoura&e you to e)periment with different structures- we'll use a simple file format that encodes the world as a list of strin&s and the rest of the data as inte&ers in a particular order! /ere is one possi#le file=

Chapter ?& ,TL ,e@uence Containers File: le#el.txt


8H 8H 8 0 ............... .Y Y. . . . . . . . . . . Y . . . . . . . . . . . 3 . . . . . . . . . . . Y . . . . . . . . . . .Y Y. ...............

1 101 1

The first two num#ers encode the num#er of rows and columns in the file- respectively! The ne)t line contains the initial snake velocity as \)- \y! The remainin& lines encode the &ame #oard- usin& the same characters we settled on for the world ve*tor! 0e'll assume that the snake is initially of len&th one and its position is &iven #y a 3 character! There are two steps necessary to let the user choose the level layout! 8irst- we need to prompt the user for the name of the file to open- repromptin& until she chooses an actual file! Second- we need to parse the contents of the file into a game; struct! 'n this e)ample we won't check that the file is formatted correctlythou&h in professional code we would certainly need to check this! 'f you'd like some additional practice with the streams li#rary- this would #e an e)cellent e)ercise! et's start writin& the function responsi#le for loadin& the file from disk- (nitialiUeGame! Since we need to prompt the user for a filename until she enters a valid file- we'll #e&in writin&=
void (nitialiUeGame(game;? game) { ifstream in$ut; 'hile(true) { *out /Enter filename4 /; string filename = Get7ine(); "3 ... 3" # "3 ... 3"

The 'hile(true) loop will continuously prompt the user until she enters a valid file! /ere- we assume that Get7ine() is the version defined in the chapter on streams! ,lso- since we're now usin& the ifstream type- we'll need to .in*lude fstream) at the top of our pro&ram! "ow that the user has &iven us the a filename- we'll try openin& it usin& the .o$en() mem#er function! 'f the file opens successfully- we'll #reak out of the loop and start readin& level data=

1 10; 1
void (nitialiUeGame(game;? game) { ifstream in$ut; 'hile(true) { *out /Enter filename4 /; string filename = Get7ine();

Chapter ?& ,TL ,e@uence Containers

in$ut.o$en(filename.*Lstr()); "" 6ee 5ha$ter C for info on .*Lstr(). if(in$ut.isLo$en()) breaB; "3 ... 3" # "3 ... 3" #

'f the file did not open- however- we need to report this to the user! ,dditionally- we have to make sure to reset the stream's error state- since openin& a none)istent file causes the stream to fail! Code for this is shown here=
void (nitialiUeGame(game;? game) { ifstream in$ut; 'hile(true) { *out /Enter filename4 /; string filename = Get7ine(); in$ut.o$en(filename.*Lstr()); "" 6ee 5ha$ter C for info on .*Lstr(). if(in$ut.isLo$en()) breaB; *out /6orr%, ( *anAt find the file / in$ut.*lear(); filename endl;

# "3 ... 3"

"ow we need to parse the file data into a game; struct! Since this is rather involved- we'll decompose it into a helper function called 7oad2orld- then finish (nitialiUeGame as follows=
void (nitialiUeGame(game;? game) { ifstream in$ut; 'hile(true) { *out /Enter filename4 /; string filename = Get7ine(); in$ut.o$en(filename.*Lstr()); "" 6ee 5ha$ter C for info on .*Lstr(). if(in$ut.isLo$en()) breaB; *out /6orr%, ( *anAt find the file / in$ut.*lear(); filename endl;

# 7oad2orld(game, in$ut);

"otice that e)cept for the call to 7oad2orld- nothin& in the code for (nitialiUeGame actually pertains to our Snake &ame! 'n fact- the code we've written is a &eneric routine for openin& a file specified #y the user! 0e'll thus #reak this function down into two functions ( =$en@ser&ile- which prompts the user for a filename- and (nitialiUeGame- which opens the specified file- then hands it off to 7oad2orld! This is shown here=

Chapter ?& ,TL ,e@uence Containers


void =$en@ser&ile(ifstream? in$ut) { 'hile(true) { *out /Enter filename4 /; string filename = Get7ine(); in$ut.o$en(filename.*Lstr()); "" 6ee 5ha$ter C for .*Lstr(). if(in$ut.isLo$en()) return; *out /6orr%, ( *anAt find the file / in$ut.*lear(); # # filename endl;

1 10@ 1

void (nitialiUeGame(game;? game) { ifstream in$ut; =$en@ser&ile(in$ut); 7oad2orld(game, in$ut); #

et's #e&in workin& on 7oad2orld! The first line of our file format encodes the num#er of rows and columns in the world- and we can read this data directly into the game; struct- as seen here=
void 7oad2orld(game;? game, ifstream? in$ut) { in$ut )) game.numIo's )) game.num5ols; game.'orld.resiUe(game.numIo's); "3 ... 3" #

0e've also resized the ve*tor to hold game.numIo's strings- &uaranteein& that we have enou&h strin&s to store the entire world! This simplifies the implementation- as you'll see momentarily! "e)t- we'll read the startin& velocity for the snake- as shown here=
void 7oad2orld(game;? game, ifstream? in$ut) { in$ut )) game.numIo's )) game.num5ols; game.'orld.resiUe(game.numIo's); in$ut )) game.d+ )) game.d%; # "3 ... 3"

,t this point- we've read in the parameters of the world- and need to start readin& in the actual world data! Since each line of the file contains one row of the &rid- we'll use getline for the remainin& read operations! There's a catch- however! Fecall that getline does not mi) well with the stream e)traction operator K))L- which we've used e)clusively so far! 'n particular- the first call to getline after usin& the stream e)traction operator will return the empty strin& #ecause the newline character delimitin& the data is still waitin& to #e read! To prevent this from &ummin& up the rest of our input operations- we'll call getline here on a dummy strin& to flush out the remainin& newline=

1 10A 1
void 7oad2orld(game;? game, ifstream? in$ut) { in$ut )) game.numIo's )) game.num5ols; game.'orld.resiUe(game.numIo's); in$ut )) game.d+ )) game.d%; string dumm%; getline(in$ut, dumm%); "3 ... 3" #

Chapter ?& ,TL ,e@uence Containers

"ow we're ready to start readin& in world data! 0e'll read in game.numIo's lines from the file directly into the game.'orld ve*tor! Since earlier we resiUed the ve*tor- there already are enou&h strings to hold all the data we'll read! The readin& code is shown #elow=
void 7oad2orld(game;? game, ifstream? in$ut) { in$ut )) game.numIo's )) game.num5ols; game.'orld.resiUe(game.numIo's); in$ut )) game.d+ )) game.d%; string dumm%; getline(in$ut, dumm%); for(int ro' = 0; ro' game.numIo's; !!ro') { getline(in$ut, game.'orld[ro']); "3 ... 3" # # "3 ... 3"

Fecall that somewhere in the level file is a sin&le 3 character indicatin& where the snake #e&ins! To make sure that we set up the snake correctly- after readin& in a line of the world data we'll check to see if it contains a star and- if so- we'll populate the game.snaBe de[ue appropriately! Usin& the .find() mem#er function on the string simplifies this task- as shown here=

Chapter ?& ,TL ,e@uence Containers


void 7oad2orld(game;? game, ifstream? in$ut) { in$ut )) game.numIo's )) game.num5ols; game.'orld.resiUe(game.numIo's); in$ut )) game.d+ )) game.d%; string dumm%; getline(in$ut, dumm%); for(int ro' = 0; ro' game.numIo's; !!ro') { getline(in$ut, game.'orld[ro']); int *ol = game.'orld[ro'].find(B6naBe;ile); if(*ol 1= string44n$os) { $oint; head; head.ro' = ro'; head.*ol = *ol; game.snaBe.$ushLba*B(head); # # # "3 ... 3"

1 10? 1

The synta) for creatin& and fillin& in the $oint; data is a #it #ulky here! 0hen we cover classes in the second half of this course you'll see a much #etter way of creatin& this $oint;! 'n the meantime- we can write a helper function to clean this code up- as shown here=
pointT BakeCointKint row- int colL ] pointT resultQ result!row Y rowQ result!col Y colQ return resultQ ^ void 7oad2orld(game;? game, ifstream? in$ut) { in$ut )) game.numIo's )) game.num5ols; game.'orld.resiUe(game.numIo's); in$ut )) game.d+ )) game.d%; string dumm%; getline(in$ut, dumm%); for(int ro' = 0; ro' game.numIo's; !!ro') { getline(in$ut, game.'orld[ro']); int *ol = game.'orld[ro'].find(B6naBe;ile); if(*ol 1= string44n$os) game.snaBe.$ushLba*B(:aBe<oint(ro', *ol)); # "3 ... 3" #

There's one last step to take care of- and that's to ensure that we set the numEaten field to zero! This edit completes 7oad2orld and the final version of the code is shown here=

1 106 1
void 7oad2orld(game;? game, ifstream? in$ut) { in$ut )) game.numIo's )) game.num5ols; game.'orld.resiUe(game.numIo's); in$ut )) game.d+ )) game.d%; string dumm%; getline(in$ut, dumm%);

Chapter ?& ,TL ,e@uence Containers

for(int ro' = 0; ro' game.numIo's; !!ro') { getline(in$ut, game.'orld[ro']); int *ol = game.'orld[ro'].find(B6naBe;ile); if(*ol 1= string44n$os) game.snaBe.$ushLba*B(:aBe<oint(ro', *ol)); # # game.numEaten = 0;

3reatR 0e've *ust finished setup and it's now time to code up the actual &ame! 0e'll #e&in #y codin& a skeleton of Iun6imulation which displays the current state of the &ame- runs the ,'- and moves the snake=
void Iun6imulation(game;? game) { "3 Wee$ loo$ing 'hile 'e havenAt eaten too mu*h. 3" 'hile(game.numEaten B:a+&ood) { <rint2orld(game); "" 9is$la% the board <erformA((game); "" 0ave the A( *hoose an a*tion if(1:ove6naBe(game)) "" :ove the snaBe and sto$ if 'e *rashed. breaB; <ause(); # 9is$la%Iesult(game); "" <ause so 'e *an see 'hatAs going on. "" ;ell the user 'hat ha$$ened

0e'll implement the functions referenced here out of order- startin& with the simplest and movin& to the most difficult! 8irst- we'll #e&in #y writin& <ause- which stops for a short period of time to make the &ame seem more fluid! The particular implementation of <ause we'll use is a busy loop- a 'hile loop that does nothin& until enou&h time has elapsed! 7usy loops are frowned upon in professional code #ecause they waste CCU power- #ut for our purposes are perfectly accepta#le! The *time) header e)ports a function called *lo*B() that returns the num#er of 4clock ticks6 that have elapsed since the pro&ram #e&an! The duration of a clock tick varies from system to system- so C++ provides the constant 57=5W6L<EIL6E5 to convert clock ticks to seconds! 0e can use *lo*B to implement a #usy loop as follows= 1. Call *lo*B() to &et the current time in clock ticks and store the result! 2. Continuously call *lo*B() and compare the result a&ainst the cached value! 'f enou&h time has passed- stop loopin&! This can #e coded as follows=

Chapter ?& ,TL ,e@uence Containers

1 10D 1

*onst double B2ait;ime = 0.8; "" <ause 0.8 se*onds bet'een frames void <ause() { *lo*BLt start;ime = *lo*B(); "" *lo*BLt is a t%$e 'hi*h holds *lo*B ti*Bs. "3 ;his loo$ does nothing e+*e$t loo$ and *he*B ho' mu*h time is left. 3 Kote that 'e have to t%$e*ast start;ime from *lo*BLt to double so 3 that the division is *orre*t. ;he static%cast&dou'le((... s%nta+ 3 is the $referred 5!! 'a% of $erforming a t%$e*ast of this sort; 3 see the *ha$ter on 3 inheritan*e for more information. 3" 'hile(stati*L*ast double)(*lo*B() - start;ime) " 57=5W6L<EIL6E5 B2ait;ime);

"e)t- let's implement the <rint2orld function- which displays the current state of the world! 0e chose to represent the world as a ve*tor string) to simplify this code- and as you can see this desi&n decision pays off well=
void <rint2orld(game;? game) { for(int ro' = 0; ro' game.numIo's; !!ro') *out game.'orld[ro'] endl; *out /&ood eaten4 / game.numEaten endl; #

This implementation of <rint2orld is fine- #ut every time it e)ecutes it adds more te)t to the console instead of clearin& what's already there! This makes it tricky to see what's happenin&! Unfortunatelystandard C++ does not e)port a set of routines for manipulatin& the console! /owever- every ma*or operatin& system e)ports its own console manipulation routines- primarily for developers workin& on a command line! 8or e)ample- on a inu) system- typin& *lear into the console will clear its contents- while on 0indows the command is 576! C++ a#sor#ed C's standard li#rary- includin& the s%stem function Kheader file *stdlib)L! s%stem e)ecutes an operatin& system1specific instruction as if you had typed it into your system's command line! This function can #e very dan&erous if used incorrectly-P #ut also &reatly e)pands the power of C++! 0e will not cover how to use s%stem in detail since it is platform1specific- #ut one particular application of system is to call the appropriate operatin& system function to clear the console! 0e can thus up&rade our implementation of <rint2orld as follows=
"3 ;he string used to *lear the dis$la% before $rinting the game board. 3 2indo's s%stems should use /576/; :a* =6 R or 7inu+ users should use 3 /*lear/ instead. 3" *onst string B5lear5ommand = /576/; void <rint2orld(game;? game) { s%stem(B5lear5ommand.*Lstr()); for(int ro' = 0; ro' game.numIo's; !!ro') *out game.'orld[ro'] endl; *out /&ood eaten4 / game.numEaten endl; #

7ecause s%stem is from the days of pure C- we have to use .*Lstr() to convert the strin& parameter into a C1style strin& #efore we can pass it into the function!
P 'n particular- callin& s%stem without checkin& that the parameters have #een sanitized can let malicious users completely compromise your system! Take CS1?? for more information on what sorts of attacks are possi#le!

1 10E 1

Chapter ?& ,TL ,e@uence Containers

The final 5uick function we'll write is 9is$la%Iesult- which is called after the &ame has ended to report whether the computer won or lost! This function is shown here=
void 9is$la%Iesult(game;? game) { <rint2orld(game); if(game.numEaten == B:a+&ood) *out /;he snaBe ate enough food and 'ins1/ else *out /=h no1 ;he snaBe *rashed1/ endl; #

endl;

"ow- on to the two tricky functions ( <erformA(- which determines the snake's ne)t move- and :ove6naBe- which moves the snake and processes collisions! 0e'll #e&in with <erformA(! 2esi&nin& an ,' that plays Snake intelli&ently is far #eyond the scope of this class! /owever- it is feasi#le to #uild a rudimentary ,' that plays reasona#ly well! Gur particular ,' works as follows= if the snake is a#out to collide with an o#*ect- the ,' will turn the snake out of dan&er! Gtherwise- the snake will continue on its current path- #ut has a percent chance to randomly chan&e direction! et's #e&in #y writin& the code to check whether the snake will turnQ that is- whether we're a#out to hit a wall or if the snake randomly decides to veer in a direction! 0e'll write a skeletal implementation of this code- then will implement the re5uisite functions! Gur initial code is
*onst double B;urnIate = 0.E; "" E0\ *han*e to turn ea*h ste$. void <erformA((game;? game) { "3 &igure out 'here 'e 'ill be after 'e move this turn. 3" $oint; ne+t0ead = GetKe+t<osition(game); "3 (f that hits a 'all or 'e randoml% de*ide to, turn the snaBe. 3" if(5rashed(ne+t0ead, game) OO Iandom5han*e(B;urnIate)) { "3 ... 3" # #

/ere we're callin& three functions we haven't written yet ( GetKe+t<osition- which computes the position of the head on the ne)t iterationQ 5rashed- which returns whether the snake would crash if its head was in the &iven positionQ and Iandom5han*eQ which returns true with pro#a#ility e5ual to the parameter! 7efore implementin& the rest of <erformA(- let's knock these functions out so we can focus on the rest of the task at hand! 0e #e&in #y implementin& GetKe+t<osition! This function accepts as input the &ame state and returns the point that we will occupy on the ne)t frame if we continue movin& in our current direction! This function isn't particularly comple) and is shown here=
$oint; GetKe+t<osition(game;? game) { "3 Get the head $osition. 3" $oint; result = game.snaBe.front(); "3 (n*rement the head $osition b% the *urrent dire*tion. 3" result.ro' != game.d%; result.*ol != game.d+; return result; #

The implementation of 5rashed is similarly strai&htforward! The snake has crashed if it has &one out of #ounds or if its head is on top of a wall or another part of the snake=

Chapter ?& ,TL ,e@uence Containers


bool 5rashed($oint; head<os, game;? game) { return 1(n2orld(head<os, game) OO game.'orld[head<os.ro'][head<os.*ol] == B6naBe;ile OO game.'orld[head<os.ro'][head<os.*ol] == B2all;ile; #

1 10< 1

/ere- (n2orld returns whether the point is in #ounds and is defined as


bool (n2orld($oint;? $t, game;? game) { return $t.*ol )= 0 ?? $t.ro' )= 0 ?? $t.*ol game.num5ols ?? $t.ro' game.numIo's; #

"e)t- we need to implement Iandom5han*e! 'n CS1067HI we provide you a header file- random.h- that e)ports this function! /owever- random.h is not a standard C++ header file and thus we will not use it here! 'nstead- we will use C++'s rand and srand functions- also e)ported #y V*stdlib_- to implement Iandom5han*e! rand() returns a pseudorandom num#er in the ran&e N0- IAK9L:ARO- where IAK9L:AR is usually ;1? ( 1! srand seeds the random num#er &enerator with a value that determines which values are returned #y rand! Gne common techni5ue is to use the time function- which returns the current system time- as the seed for srand since different runs of the pro&ram will yield different random seeds! Traditionally- you will only call srand once per pro&ram- prefera#ly durin& initialization! 0e'll thus modify (nitialiUeGame so that it calls srand in addition to its other functionality=
void (nitialiUeGame(game;? game) { "3 6eed the randomiUer. ;he stati*L*ast *onverts the result of time(K@77) 3 from timeLt to the unsigned int re[uired b% srand. ;his line is 3 idiomati* 5!!. 3" srand(stati*L*ast unsigned int)(time(K@77))); ifstream in$ut; =$en@ser&ile(in$ut); 7oad2orld(game, in$ut);

"ow- let's implement Iandom5han*e! To write this function- we'll call rand to o#tain a value in the ran&e N0- IAK9L:ARO- then divide it #y IAK9L:AR ! 8.0 to &et a value in the ran&e N0- 1L! 0e can then return whether this value is less than the input pro#a#ility! This yields true with the specified pro#a#ilityQ try convincin& yourself that this works if it doesn't immediately seem o#vious! This is a common techni5ue and in fact is how the CS1067HI Iandom5han*e function is implemented!
Iandom5han*e is shown here= bool Iandom5han*e(double $robabilit%) { return (rand() " (IAK9L:AR ! 8.0)) # $robabilit%;

"otice that we added 1!0 to IAK9L:AR! This #oth adds the +1 necessary from the a#ove discussion and implicitly converts the denominator into a double- which is necessary to avoid inte&er truncation! ChewR ,polo&ies for the len&thy detour ( let's &et #ack to writin& the ,'R Fecall that we've written this code so far=

1 110 1

Chapter ?& ,TL ,e@uence Containers

void <erformA((game;? game) { "3 &igure out 'here 'e 'ill be after 'e move this turn. 3" $oint; ne+t0ead = GetKe+t<osition(game); "3 (f that $uts us into a 'all or 'e randoml% de*ide to, turn the snaBe. 3" if(5rashed(ne+t0ead, game) OO Iandom5han*e(B;urnIate)) { "3 ... 3" # #

0e now need to implement the lo&ic for turnin& the snake left or ri&ht! 8irst- we'll fi&ure out in what positions the snake's head would #e if we turned left or ri&ht! Then- #ased on which of these positions are safe- we'll pick a direction to turn! To avoid code duplication- we'll modify our implementation of GetKe+t<osition so that the caller can specify the direction of motion- rather than relyin& on the game;'s stored direction! The modified version of GetKe+t<osition is shown here=
$oint; GetKe+t<osition(game;? game, int d+, int d%) { "3 Get the head $osition. 3" game; result = game.snaBe.front(); "3 (n*rement the head $osition b% the s$e*ified dire*tion. 3" result.ro' != d%; result.*ol != d+; return result;

0e'll need to modify <erformA( to pass in the proper parameters to GetKe+t<osition- as shown here=
void <erformA((game;? game) { "3 &igure out 'here 'e 'ill be after 'e move this turn. 3" $oint; ne+t0ead = GetKe+t<osition(game, game.d+, game.d%); "3 (f that $uts us into a 'all or 'e randoml% de*ide to, turn the snaBe. 3" if(5rashed(ne+t0ead, game) OO Iandom5han*e(B;urnIate)) { "3 ... 3" #

"ow- let's write the rest of this code! 3iven that the snake's velocity is K game.d+- game.d%L- what velocities would we move at if we were headin& ninety de&rees to the left or ri&ht> Usin& some #asic linear al&e#ra-P if our current headin& is alon& d) and dy- then the headin&s after turnin& left and ri&ht from our current headin& are #e &iven #y d)left Y 1dy dyleft Y d) d)ri&ht Y dy dyri&ht Y 1d) Usin& these e5ualities- we can write the followin& code- which determines what #earin&s are availa#le and whether it's safe to turn left or ri&ht=

P This is the result of multiplyin& the vector Kd)- dyLT #y a rotation matri) for either +9H; or 19H; radians!

Chapter ?& ,TL ,e@uence Containers


void <erformA((game;? game) { "3 &igure out 'here 'e 'ill be after 'e move this turn. 3" $oint; ne+t0ead = GetKe+t<osition(game, game.d+, game.d%);

1 111 1

"3 (f that $uts us into a 'all or 'e randoml% de*ide to, turn the snaBe. 3" if(5rashed(ne+t0ead, game) OO Iandom5han*e(B;urnIate)) { int left9+ = -game.d%; int left9% = game.d+; int right9+ = game.d%; int right9% = -game.d+; "3 5he*B if turning left or right 'ill *ause us to *rash. 3" bool *an7eft = 15rashed(GetKe+t<osition(game, left9+, left9%), game); bool *anIight = 15rashed(GetKe+t<osition(game, right9+, right9%), game); # # "3 ... 3"

"ow- we'll decide which direction to turn! 'f we can only turn one direction- we will choose that direction! 'f we can't turn at all- we will do nothin&! 8inally- if we can turn either direction- we'll pick a direction randomly! 0e will store which direction to turn in a #oolean varia#le called 'ill;urn7eft which is true if we will turn left and false if we will turn ri&ht! This is shown here=
void <erformA((game;? game) { "3 &igure out 'here 'e 'ill be after 'e move this turn. 3" $oint; ne+t0ead = GetKe+t<osition(game, game.d+, game.d%); "3 (f that $uts us into a 'all or 'e randoml% de*ide to, turn the snaBe. 3" if(5rashed(ne+t0ead, game) OO Iandom5han*e(B;urnIate)) { int left9+ = -game.d%; int left9% = game.d+; int right9+ = game.d%; int right9% = -game.d+; "3 5he*B if turning left or right 'ill *ause us to *rash. 3" bool *an7eft = 15rashed(GetKe+t<osition(game, left9+, left9%), game); bool *anIight = 15rashed(GetKe+t<osition(game, right9+, right9%), game); bool 'ill;urn7eft = false; if(1*an7eft ?? 1*anIight) return; "" (f 'e *anAt turn, donAt turn. else if(*an7eft ?? 1*anIight) 'ill;urn7eft = true; "" (f 'e must turn left, do so. else if(1*an7eft ?? *anIight) 'ill;urn7eft = false; "" (f 'e must turn right, do so. else 'ill;urn7eft = Iandom5han*e(0.H); "" Else $i*B randoml% "3 ... 3" # #

1 11; 1 8inally- we'll update our direction vector #ased on our choice=

Chapter ?& ,TL ,e@uence Containers

void <erformA((game;? game) { "3 &igure out 'here 'e 'ill be after 'e move this turn. 3" $oint; ne+t0ead = GetKe+t<osition(game, game.d+, game.d%); "3 (f that $uts us into a 'all or 'e randoml% de*ide to, turn the snaBe. 3" if(5rashed(ne+t0ead, game) OO Iandom5han*e(B;urnIate)) { int left9+ = -game.d%; int left9% = game.d+; int right9+ = game.d%; int right9% = -game.d+; "3 5he*B if turning left or right 'ill *ause us to *rash. 3" bool *an7eft = 15rashed(GetKe+t<osition(game, left9+, left9%), game); bool *anIight = 15rashed(GetKe+t<osition(game, right9+, right9%), game); bool 'ill;urn7eft = false; if(1*an7eft ?? 1*anIight) return; "" (f 'e *anAt turn, donAt turn. else if(*an7eft ?? 1*anIight) 'ill;urn7eft = true; "" (f 'e must turn left, do so. else if(1*an7eft ?? *anIight) 'ill;urn7eft = false; "" (f 'e must turn right, do so. else 'ill;urn7eft = Iandom5han*e(0.H); "" Else $i*B randoml% game.d+ = 'ill;urn7eftT left9+ 4 right9+; game.d% = 'ill;urn7eftT left9% 4 right9%;

# #

'f you're not familiar with the T4 operator- the synta) is as follows=
expression T result-if-true 4 result-if-false

/ere- this means that we'll set game.d+ to left9+ if 'ill;urn7eft is true and to right9+ otherwise! 0e now have a workin& version of <erformA(! Gur resultin& implementation is not particularly denseand most of the work is factored out into the helper functions! There is one task left ( implementin& :ove6naBe! Fecall that :ove6naBe moves the snake one step forward on its path! 'f the snake crashes- the function returns false to indicate that the &ame is over! Gtherwise- the function returns true! The first thin& to do in :ove6naBe is to fi&ure out where the snake's head will #e after takin& a step! Thanks to GetKe+t<osition- this has already #een taken care of for us=
bool :ove6naBe(game;? game) { $oint; ne+t0ead = GetKe+t<osition(game, game.d+, game.d%); "3 ... 3" #

Chapter ?& ,TL ,e@uence Containers

1 11@ 1

"ow- if we crashed into somethin& Keither #y fallin& off the map or #y hittin& an o#*ectL- we'll return false so that the main loop can terminate=
bool :ove6naBe(game;? game) { $oint; ne+t0ead = GetKe+t<osition(game, game.d+, game.d%); if(5rashed(ne+t0ead, game)) return false; # "3 ... 3"

"e)t- we need to check to see if we ate some food! 0e'll store this in a bool varia#le for now- since the lo&ic for processin& food will come a #it later=
bool :ove6naBe(game;? game) { $oint; ne+t0ead = GetKe+t<osition(game, game.d+, game.d%); if(5rashed(ne+t0ead, game)) return false; bool is&ood = (game.'orld[ne+t0ead.ro'][ne+t0ead.*ol] == B&ood;ile); # "3 ... 3"

"ow- let's update the snake's head! 0e need to update the 'orld ve*tor so that the user can see that the snake's head is in a new s5uare- and also need to update the snaBe de[ue so that the snake's head is now &iven #y the new position! This is shown here=
bool :ove6naBe(game;? game) { $oint; ne+t0ead = GetKe+t<osition(game, game.d+, game.d%); if(5rashed(ne+t0ead, game)) return false; bool is&ood = (game.'orld[ne+t0ead.ro'][ne+t0ead.*ol] == B&ood;ile); game.'orld[ne+t0ead.ro'][ne+t0ead.*ol] = B6naBe;ile; game.snaBe.$ushLfront(ne+t0ead); # "3 ... 3"

8inally- it's time to move the snake's tail forward one step! /owever- if we've eaten any food- we will leave the tail as1is so that the snake &rows #y one tile! 0e'll also put food someplace else on the map so the snake has a new o#*ective! The code for this is shown here=

1 11A 1

Chapter ?& ,TL ,e@uence Containers

bool :ove6naBe(game;? game) { $oint; ne+t0ead = GetKe+t<osition(game, game.d+, game.d%); if(5rashed(ne+t0ead, game)) return false; bool is&ood = (game.'orld[ne+t0ead.ro'][ne+t0ead.*ol] == B&ood;ile); game.'orld[ne+t0ead.ro'][ne+t0ead.*ol] = B6naBe;ile; game.snaBe.$ushLfront(ne+t0ead); if(1is&ood) { game.'orld[game.snaBe.ba*B().ro'][game.snaBe.ba*B().*ol] = BEm$t%;ile; game.snaBe.$o$Lba*B(); # else { !!game.numEaten; <la*e&ood(game); # return true; #

0e're nearin& the home stretch ( all that's left to do is to implement <la*e&ood and we're doneR This function is simple ( we'll *ust sit in a loop pickin& random locations on the #oard until we find an empty spot- then will put a piece of food there! To &enerate a random location on the #oard- we'll scale rand() down to the proper ran&e usin& the modulus K \L operator! 8or e)ample- on a world with four rows and ten columns- we'd pick as a row rand() \ G and as a column *ol() \ 80! The code for this function is shown here=
void <la*e&ood(game;? game) { 'hile(true) { int ro' = rand() \ game.numIo's; int *ol = rand() \ game.num5ols; "3 (f the s$e*ified $osition is em$t%, $la*e the food there. 3" if(game.'orld[ro'][*ol] == BEm$t%;ile) { game.'orld[ro'][*ol] = B&ood;ile; return; #

# #

Chapter ?& ,TL ,e@uence Containers (ore To )*+lore

1 11? 1

There's so much to e)plore with the ST that we could easily fill the rest of the course reader with ST content! 'f you're interested in some more advanced topics relatin& to this material and the ST in &eneralconsider readin& on these topics= 1. stac' and &ueue= The ve*tor and de[ue pack a lot of firepower and can solve a wide array of pro#lems! /owever- in some cases- you may want to use a container with a more restricted set of operations! 8or these purposes- the ST e)ports two container adapters- containers that e)port functionality similar to a ve*tor or de[ue #ut with a sli&ht reduction in power! The first of these is the sta*B- which only lets you view the final element of a se5uenceQ the second is the [ueuewhich is similar to line at a ticket counter! 'f you plan on pursuin& C++ more seriously- you should take the time to look over what these container adapters have to offer! 2. #alarray= The valarra% class is similar to a ve*tor in that it's a mana&ed array that can hold elements of any type! /owever- unlike ve*tor- valarra% is desi&ned for numerical computations! valarra%s are fi)ed1size and have intrinsic support for mathematical operators! 8or e)ample- you can use the synta) m%JalArra% 3= E to multiply all of the entries in a valarra% #y two! 'f you're interested in numeric or computational pro&rammin&- consider lookin& into the valarra%! 3. There's an e)cellent article online comparin& the performances of the ve*tor and de[ue containers! 'f you're interested- you can see it at http=HHwww!codepro*ect!comHvcppHstlHvector[vs[de5ue!asp! !ractice !roblems 1. ist two differences #etween the ve*tor's $ushLba*B and resiUe mem#er functions!

2. 0hat header files do you need to .in*lude to use ve*tor> de[ue> 3. /ow do you tell how many elements are in a ve*tor> 'n a de[ue> 4. /ow do you remove the first element from a ve*tor> 8rom a de[ue> . 0rite a function called 7ines&rom&ile which takes in a strin& containin& a filename and returns a ve*tor string) containin& all of the lines of te)t in the file in the order in which they appear! 'f the file does not e)ist- you can return an empty ve*tor! 5+int& loo* at the code $or reading the world $ile in the ,na*e e4ample and see i$ you can modi$y it appropriately6 !. Update the code for the sortin& pro&ram so that it sorts elements in descending order instead of ascending order! $. Gne use for the de[ue container is to create a ring bu$$er! Unlike the linear ve*tor and de[ue containers you saw in this chapter- a rin& #uffer is circular! /ere's an illustration of a rin& #uffer=

1 116 1

Chapter ?& ,TL ,e@uence Containers

11 10 ,

1 ( 3 ) *
Cursor

, rin& #uffer consists of a circular rin& of elements with a cursor which selects some particular element out of the #uffer! The four main operations on a rin& #uffer are as follows= Fotate the rin& clockwise Fotate the rin& counterclockwise Fead the value at the cursor! 0rite the value at the cursor!

8or e)ample- &iven the a#ove rin& #uffer- the result of rotatin& the rin& clockwise would #e

10 , +

11

0 1 ( 3 )
Cursor

'f we then wrote the value ? to the location specified #y the cursor- the #uffer would look like this=

10 , +

11

0 1 * 3 )
Cursor

Chapter ?& ,TL ,e@uence Containers

1 11D 1

There is a particularly ele&ant construction which ena#les us to #uild a rin& #uffer out of a de[ue! The #asic idea is to 4unroll6 the rin& #uffer into a linear se5uence- then use a com#ination of $ushLfront- $o$Lfront- $ushLba*B- and $o$Lba*B to simulate movin& the cursor to the left or to the ri&ht! This techni5ue of simulatin& one data structure usin& another is u#i5uitous in computer science- and many important results in computa#ility theory use constructions of this form! To see e)actly how the construction works- suppose that we have the followin& rin& #uffer=

11 10 ,

1 ( 3 ) *
Cursor

+ 0

0e can then represent this usin& a de[ue as follows=

11 10 ,

1 ( 3 ) *
, - 10 11 0 1 (
Cursor

+
3 ) * +

That is- the first element of the de[ue is the element under the cursor- and the rest of the elements in the de[ue are the elements in the rin& #uffer formed #y walkin& clockwise around the rin& #uffer! 3iven this construction- we can simulate rotatin& the rin& one position clockwise #y movin& the last element of the de[ue onto the front- as shown here=

1 11E 1

Chapter ?& ,TL ,e@uence Containers

10 , +

11

0 1 ( 3 )
, - 10 11 0 1
Cursor

( 3 ) * +

Similarly- to move the cursor one step counterclockwise- we move the element at the end of the de[ue onto the front- as shown here=

11 10 ,

1 ( 3 ) *
, - 10 11 0 1 (
Cursor

+
3 ) * +

0rite a pair of functions 5ursor5lo*B'ise and 5ursor5ounter5lo*B'ise which take in a de[ue representin& a rin& #uffer and update the de[ue #y simulatin& a cursor move in either direction! Then write functions 5ursorIead and 5ursor2rite which read and write the element stored at the cursor! .ou've *ust shown how to represent one data structure usin& anotherR

Chapter ?& ,TL ,e@uence Containers

1 11< 1

6. ,s mentioned earlier- the de[ue outperforms the vector when insertin& and removin& elements at the end of the container! /owever- the ve*tor has a useful mem#er function called reserve that can #e used to increase its performance a&ainst the de[ue in certain circumstances! The reserve function accepts an inte&er as a parameter and acts as a sort of 4size hint6 to the ve*tor! 7ehind the scenes- reserve works #y allocatin& additional stora&e space for the ve*tor elementsreducin& the num#er of times that the ve*tor has to ask for more stora&e space! Gnce you have called reserve- as lon& as the size of the ve*tor is less than the num#er of elements you have reserved- calls to $ushLba*B and insert on the ve*tor will e)ecute more 5uickly than normal! Gnce the ve*tor hits the size you reserved- these operations revert to their ori&inal speed! P 0rite a pro&ram that uses $ushLba*B to insert a lar&e num#er of strings into two different ve*tors ( one which has had reserve called on it and one which hasn't ( as well as a de[ue! The e)act num#er and content of strin&s is up to you- #ut lar&e num#ers of lon& strin&s will &ive the most impressive results! Use the *lo*B() function e)ported #y *time) to compute how lon& it takes to finish insertin& the strings! "ow repeat this trial- #ut insert the elements at the #e&innin& of the container rather than the end! 2id callin& reserve help to make the ve*tor more competitive a&ainst the de[ue: 7. 'n this ne)t pro#lem we'll e)plore a simple encryption al&orithm called the BigenCre cipher and how to implement it usin& the ST containers! Gne of the oldest known ciphers is the Caesar cipher- named for $ulius Caesar- who alle&edly employed it! The idea is simple! 0e pick a secret num#er #etween 1 and ;6- inclusive- then encrypt the input strin& #y replacin& each letter with the letter that comes that many spaces after it! 'f this pushes us off the end of the alpha#et- we wrap around to the start of the alpha#et! 8or e)ample- if we were &iven the strin& 4The cookies are in the frid&e6 and picked the num#er 1- we would end up with the resultin& strin& 4Uif dppl*ft #sf *o uif &s*ehf!6 To decrypt the strin&- we simply need to push each letter #ackwards #y one spot! The Caesar cipher is an e)tremely weak form of encryptionQ it was #roken in the ninth century #y the ,ra# polymath al1Kindi! The pro#lem is that the cipher preserves the relative fre5uencies of each of the letters in the source te)t! "ot all letters appear in Jn&lish with e5ual fre5uency ( e and t are far more common than 5 or w- for e)ample ( and #y lookin& at the relative letter fre5uencies in the encrypted te)t it is possi#le to determine which letter in the encrypted te)t corresponds to a letter in the source te)t and to recover the key! The pro#lem with the Caesar cipher is that it preserves letter fre5uencies #ecause each letter is transformed usin& the same key! 7ut what if we were to use multiple keys while encryptin& the messa&e> That is- we mi&ht encrypt the first letter with one key- the second with another- the third with yet another- etc! Gne way of doin& this is to pick a se5uence of num#ers- then cycle throu&h them while encryptin& the te)t! 8or e)ample- let's suppose that we want to encrypt the a#ove messa&e usin& the key strin& 1- @- D! Then we would do the followin&=
T 1 G / @ C J D = C 1 D G @ 4 G D K K 1 = ' @ = J D = S 1 T , @ D F D M J 1 2 ' @ = " D G T 1 G / @ C J D = 8 1 F @ G ' D ! 2 1 ) 3 @ ? J D =

"otice that the letters K'J from CGGK'JS are all mapped to the letter - makin& cryptanalysis much more difficult! This particular encryption system is the Ti&en`re cipher!
P Callin& $ushLba*B n times always takes GKnL time- whether or not you call reserve! /owever- callin& reserve reduces the constant term in the #i&1G to a smaller value- meanin& that the overall e)ecution time is lower!

1 1;0 1

Chapter ?& ,TL ,e@uence Containers "ow- let's consider what would happen if we wanted to implement this al&orithm in C++ to work on ar#itrary strin&s! Strin&s in C++ are composed of individual chars- which can take on KtypicallyL one of ;?6 different values! 'f we had a list of inte&er keys- we could encrypt a strin& usin& the Ti&en`re cipher #y simply cyclin& throu&h those keys and incrementin& the appropriate letters of the strin&! 'n fact- the al&orithm is 5uite simple! 0e iterate over the characters of the strin&- at each point incrementin& the character #y the current key and then rotatin& the keys one cycle! a. Suppose that we want to represent a list of inte&er keys that can easily #e cycledQ that is- we want to efficiently support movin& the first element of the list to the #ack! Gf the containers covered in this chapter Kve*tor and de[ueL- which have the #est support for this operation> b. 7ased on your decision- implement a function JigenereEn*r%$t that accepts a strin& and a list of int keys stored in the container of your choice- then encrypts the strin& usin& the Ti&en`re cipher!

C.a+ter N8 6T= Associati;e Containers and Iterators


[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ 'n the previous chapter- we e)plored two of the ST 's se5uence containers- the ve*tor and de[ue! These containers are ideally suited for situations where we need to keep track of an ordered list of elementssuch as an itinerary- shoppin& list- or mathematical vector! /owever- representin& data in ordered lists is not optimal in many applications! 8or e)ample- when keepin& track of what merchandise is sold in a particular store- it does not make sense to think of the products as an ordered list! Storin& merchandise in a list would imply that the merchandise could #e ordered as 4this is the first item #ein& sold- this is the second item #ein& sold- etc!6 'nstead- it makes more sense to treat the collection of merchandise as an unordered collection- where membership rather than ordering is the definin& characteristic! That is- we are more interested in answers to the 5uestion 4is item I #ein& sold here>6 than answers to the 5uestion 4where in the se5uence is the element I>6 ,nother scenario in which ordered lists are su#optimal arises when tryin& to represent relationships #etween sets of data! 8or e)ample- we may want to encode a mappin& from street addresses to #uildin&s- or from email addresses to names! 'n this setup- the main 5uestion we are interested in answerin& is 4what value is associated with I>-6 not 4where in the se5uence is element I>6 'n this chapter- we will e)plore four new ST container classes ( ma$- set- multima$- and multiset ( that provide new a#stractions for storin& data! These containers will represent allow us to ask different 5uestions of our data sets and will make it possi#le to write pro&rams to solve increasin&ly comple) pro#lems! ,s we e)plore those containers- we will introduce ,TL iterators- tools that will pave the way for more advanced ST techni5ues! 6toring Gnordered Collections wit. set To motivate the ST set container- let's consider a simple pro#a#ility 5uestion! Fecall from last chapter's ,na*e e)ample that the C++ rand() function can #e used to &enerate a pseudorandom inte&er in the ran&e N0- IAK9L:ARO! KFecall that the notation Na- bO represents all real num#ers #etween a and b- inclusiveL! Commonly- we are interested not in values from zero to IAK9L:AR- #ut instead values from 0 to some set upper #ound *! To &et values in this ran&e- we can use the value of
rand() \ (B ! 8)

This computes the remainder when dividin& rand() #y * + 1- which must #e in the ran&e N0- *O!P "ow- consider the followin& 5uestion! Suppose that we have a si)1sided die! 0e roll the die- then record what num#er we rolled! 0e then keep rollin& the die and record what num#er came up- and keep repeatin& this process! The 5uestion is as follows= how many times- on avera&e- will we roll the die #efore the same num#er comes up twice> This is actually a special case of a more &eneral pro#lem= if we continuously &enerate random inte&ers in the ran&e N0- *O- how many num#ers should we e)pect to &enerate #efore we &enerate some num#er twice> 0ith some fairly advanced pro#a#ility theory- this value can #e calculated e)actly! /owever- this is a te)t#ook on C++ pro&rammin&- not pro#a#ility theoryand so we'll write a short pro&ram that will simulate this process and report the avera&e num#er of die rolls!

P This process will not always yield uniformly1distri#uted values- #ecause IAK9L:AR will not always #e a multiple of *! 8or a fun math e)ercise- think a#out why this is!

1 1;; 1

Chapter =& ,TL Associative Containers and Iterators

There are many ways that we can write this pro&ram! 'n the interest of simplicity- we'll #reak the pro&ram into two separate tasks! 8irst- we'll write a function that rolls the die over and over a&ain- then reports how many die rolls occurred #efore some num#er came up twice! Second- we'll write our main function to call this function multiple times to &et a &ood sample- then will have it print out the avera&e! et's think a#out how we can write a function that rolls a die until the same num#er comes up twice! ,t a hi&h level- this function needs to &enerate a random num#er from 1 to 6- then check if it has #een &enerated #efore! 'f so- it should stop and report the num#er of dice rolled! Gtherwise- it should remem#er that this num#er has #een rolled- then &enerate a new num#er! , key step of this process is remem#erin& what num#ers have come up #efore- and usin& the techni5ues we've covered so far we could do this usin& either a ve*tor or a de[ue! 8or simplicity- we'll use a ve*tor! Gne implementation of this function looks like this=
"3 Iolls a si+-sided die and returns the number that *ame u$. 3" int 9ieIoll() { "3 rand() \ N gives ba*B a value bet'een 0 and H, in*lusive. 3 this gives us a valid number for a die roll. 3" return (rand() \ N) ! 8; #

Adding one to

"3 Iolls the di*e until a number a$$ears t'i*e, then re$orts the number of die 3 rolls. 3" siUeLt Iun<ro*ess() { ve*tor int) generated; 'hile (true) { "3 Ioll the die. 3" int ne+tJalue = 9ieIoll(); "3 6ee if this value has *ome u$ before. (f so, return the number of 3 rolls re[uired. ;his is e[ual to the number of di*e that have been 3 rolled u$ to this $oint, $lus one for this ne' roll. 3" for (siUeLt B = 0; B generated.siUe(); !!B) if (generated[B] == ne+tJalue) return generated.siUe() ! 8; "3 =ther'ise, remember this die roll. 3" generated.$ushLba*B(ne+tJalue); # #

"ow that we have the Iun<ro*ess function written- we can run throu&h one simulation of this process! /owever- it would #e silly to &ive an estimate #ased on *ust one iteration! To &et a &ood estimate- we'll need to run this process multiple times to control for randomness! Conse5uently- we can write the followin& main function- which runs the process multiple times and reports the avera&e value=

Chapter =& ,TL Associative Containers and Iterators


*onst siUeLt BKum(terations = 80000; "" Kumber of iterations to run

1 1;@ 1

int main() { "3 6eed the randomiUer. 6ee the last *ha$ter for more information on this 3 line. 3" srand(stati*L*ast unsigned)(time(K@77))); siUeLt total = 0; "" ;otal number of di*e rolled "3 Iun the $ro*ess BKum(terations times, a**umulating the result into 3 total. 3" for (siUeLt B = 0; B BKum(terations; !!B) total != Iun<ro*ess(); "3 &inall%, re$ort the result. 3" *out /Average number of ste$s4 / double(total) " BKum(terations

endl;

'f you compile and run this pro&ram- you'll see output that looks somethin& like this=
.#erage number of steps" 3. , 3

.ou mi&ht see a different num#er displayed on your system- since the pro&ram involves a fundamentally random process! "ow- let's make a small tweak to this pro&ram! Suppose that instead of rollin& a si)1sided die- we roll a twenty1sided die!P /ow many steps should we e)pect this to take now> 'f we chan&e our implementation of 9ieIoll to the followin&=
int 9ieIoll() { return (rand() \ E0) ! 8; #

Then runnin& the pro&ram will produce output alon& the followin& lines=
.#erage number of steps" +.(,0+

This is interestin& ( we more than tripled the num#er of sides on the die Kfrom si) to twentyL- #ut the total num#er of e)pected rolls increased #y less than a factor of twoR 's this a coincidence- or is there some fundamental law of pro#a#ility at work here> To find out- let's assume that we're now rollin& a die with @6? sides Ki!e! one side for every day of the yearL! This means our new implementation of 9ieIoll is
int 9ieIoll() { return (rand() \ CNH) ! 8; #

Funnin& this pro&ram produces output that looks like this=


.#erage number of steps" ().+ -*

P 'f you haven't seen a twenty1sided die Kor #1% in &amer1speakL- you're really missin& out! They're very fun to play with!

1 1;A 1

Chapter =& ,TL Associative Containers and Iterators

"ow that)s weirdR 'n increasin& the num#er of sides on the die from ;0 to @6?- we increased the num#er of sides on the die #y a factor of Krou&hlyL ei&hteen! /owever- the num#er of e)pected rolls went up only #y a factor of fourR 7ut more importantly- think a#out what this result means! 'f you have a roomful of people with twenty1five people- then you should e)pect at least two people in that room to have the same #irthdayR This is sometimes called the birthday parado4- since it seems counterintuitive that such a small sample of people would cause this to occur! The more &eneral result- for those of you who are interestedis that you will need to roll an n sided die rou&hly n times #efore the same num#er will come up twice! This has #een a fun diversion into the realm of pro#a#ility theory- #ut what does it have to do with C++ pro&rammin&> The answer lies in the implementation of the Iun<ro*ess function! The heart of this function is a for loop that checks whether a particular value is contained inside of a ve*tor! This loop is reprinted here for simplicity=
for (siUeLt B = 0; B generated.siUe(); !!B) if (generated[B] == ne+tJalue) return generated.siUe() ! 8;

"otice that there is a disparity #etween the hi&h1level operation #ein& modeled here K4check if the num#er has already #een &enerated6L and the actual implementation K4loop over the ve*tor- checkin&- for each element- whether that element is e5ual to the most1recently &enerated num#er6L! There is a tension here #etween what the code accomplishes and the way in which it accomplishes it! The reason for this is that we're usin& the wrong abstraction! 'ntuitively- a ve*tor maintains an ordered se@uence of elements! The main operations on a ve*tor maintain that se5uence #y addin& and removin& elements from that se5uence- lookin& up elements at particular positions in that se5uence- etc! 8or this application- we want to store a collection of num#ers that is unordered! 0e don't care when the elements were added to the ve*tor or what position they occupy! 'nstead- we are interested what elements are in the ve*tor- and in particular whether a &iven element is in the ve*tor at all! 8or situations like these- where the contents of a collection of elements are more important than the actual se@uence those elements are in- the ST provides a special container called the set! The set container represents an ar#itrary- unordered collection of elements and has &ood support for the followin& operations= ,ddin& elements to the collection! Femovin& elements from the collection! 2eterminin& whether a particular element is in the collection!

To see the set in action- let's consider a modified version of the Iun<ro*ess function which uses a set instead of a ve*tor to store its elements! This code is shown here Kthou&h you'll need to .in*lude set) for it to compileL=
siUeLt Iun<ro*ess() { set int) generated; 'hile (true) { int ne+tJalue = 9ieIoll(); "3 5he*B if this value has been rolled before. 3" if (generated.*ount(ne+tJalue)) return generated.siUe() ! 8; "3 =ther'ise, add this value to the set. 3" generated.insert(ne+tJalue);

# #

Chapter =& ,TL Associative Containers and Iterators

1 1;? 1

Take a look at the chan&es we made to this code! To determine whether the most1recently1&enerated num#er has already #een produced- we can use the simple synta) generated.*ount(ne+tJalue) rather than the clunkier for loop from #efore! ,lso notice that to insert the new element into the set- we used the insert function rather than $ushLba*B! The names of the functions on the set are indicative of the differences #etween the set and the ve*tor and de[ue! 0hen insertin& an element into a ve*tor or de[ue- we needed to specify where to put that element= at the end usin& $ushLba*B- at the #e&innin& with $ushLfront- or at some ar#itrary position usin& insert! The set has only one function for addin& elements ( insert ( which does not re5uire us to specify where in the set the element should &o! This makes sense- since the set is an inherently unordered collection of elements! ,dditionally- the set has no way to 5uery elements at specific positionssince the elements of a set don't have positions! /owever- we can check whether an element e)ists in a set very simply usin& the *ount function- which returns true if the element e)ists and false otherwise!P 'f you rerun this pro&ram usin& the updated code- you'll find that the pro&ram produces almost identical output Kthe randomness will mean that you're unlikely to &et the same output twiceL! The only difference #etween the old code and the new code is the internal structure! Usin& the set- the code is easier to read and understand! 'n the ne)t section- we'll pro#e the set in more detail and e)plore some of its other uses! A !rimer on set The ST set container represents an unordered collection of elements that does not permit duplicates! o&ically- a set is a collection of uni5ue values that efficiently supports insertin& and removin& elementsas well as checkin& whether a particular element is contained in the set! ike the ve*tor and de[ue- the set is a parameterized class! Thus we can speak of a set int)- a set double)- set string)- etc! ,s with ve*tor and de[ue- sets can only hold one type of element- so you cannot have a set that mi)es and matches #etween ints and strings- for e)ample! /owever- unlike the ve*tor or de[ue- set can only store o#*ects that can #e compared usin& the operator! This means that you can store all primitive types in a set- alon& with strings and other ST containers! /owever- you cannot store custom stru*ts inside of an ST set! 8or e)ample- the followin& is ille&al=
stru*t <oint { double +, %; #; set <oint) m%6et; // Illegal0 1oint cannot be compared with 2

This may seem like a somewhat ar#itrary restriction! o&ically- we could #e a#le to &ather up anythin& into an unordered collection! 0hy does it matter that those elements #e compara#le usin& > The answer has to do with how the set is implemented #ehind the scenes! 'nternally- the set is layered on top of a balanced binary tree- a special data structure that naturally supports the set's main operations! /owever#alanced #inary trees can only #e constructed on data sets where elements can #e compared to one another- hence the restriction! ater in this te)t we'll see how to use a techni5ue called operator overloading to make it possi#le to store o#*ects of any type in an ST set- #ut for now you will need to confine yourself to primitives and other ST containers! ,s we saw in the previous e)ample- one of the most #asic set operations is insertion usin& the insert function! Unlike the de[ue and ve*tor insert functions- you do not need to specify a location for the new element! ,fter all- a set represents an unordered collection- and specifyin& where an element should &o in a set does not make any sense! /ere is some sample code usin& insert=
P Technically speakin&- *ount returns 1 if the element e)ists and 0 otherwise! 8or most purposes- thou&h- it's safe to treat the function as thou&h it returns a #oolean true or false!

1 1;6 1
set int) m%6et; m%6et.insert(8CD); m%6et.insert(GE); m%6et.insert(8CD);

Chapter =& ,TL Associative Containers and Iterators


"" Ko' *ontains4 8CD "" Ko' *ontains4 GE 8CD "" Ko' *ontains4 GE 8CD

"otice in this last line that insertin& a second copy of 1@D into the set did not chan&e the contents of the set! sets do not allow for duplicate elements! To check whether a particular element is contained in an ST set- you can also use the *ount functionwhich returns 1 if the element is contained in the set and 0 otherwise! Usin& C++'s automatic conversion of nonzero values into true and zero values to false- you usually do not need to e)plicitly check whether *ount yields a one or zero and can rely on implicit conversions instead! 8or e)ample=
if(m%6et.*ount(8CD)) *out /8CD is in the set./ endl; "" <rinted if(1m%6et.*ount(H00)) *out /H00 is not in the set./ endl; "" <rinted

To remove an element from a set- you use the erase function! erase is a mirror to insert- and the two have very similar synta)! 8or e)ample=
m%6et.erase(8CD); "" Iemoves 8CD, if it e+ists.

The ST set also supports several operations common to all ST containers! .ou can remove all elements from a set usin& *lear- check how many elements are present usin& siUe- etc! , full ta#le of all set operations is presented later in this chapter! Tra;ersing Containers wit. Iterators Gne of the most common operations we've seen in the course of workin& with the ST containers is iteration- traversin& the contents of a container and performin& some task on every element! 8or e)amplethe followin& loop iterates over the contents of a ve*tor- printin& each element=
for (siUeLt h = 0; h m%Je*tor.siUe(); !!h) *out m%Je*tor[h] endl;

0e can similarly iterate over a de[ue as follows=


for (siUeLt h = 0; h m%9e[ue.siUe(); !!h) *out m%9e[ue[h] endl;

The reason that we can use this convenient synta) to traverse the contents of the ve*tor and de[ue is #ecause the ve*tor and de[ue represent linear se5uences- and so it is possi#le to enumerate all possi#le indices in the container usin& the standard for loop! That is- we can iterate so easily over a ve*tor or de[ue #ecause we can look up the zeroth element- then the first element- then the second- etc! Unfortunately- this lo&ic does not work on the ST set! 7ecause the set does not have an orderin& on its elements- it does not make sense to speak of the 4zeroth element of a set-6 nor the 4first element of a set-6 etc! To traverse the elements of a set- we will need to use a new concept- the iterator! Jvery ST container presents a different means of storin& data! ve*tor and de[ue store data in an ordered list! set stores its data as an unordered collection! ,s you'll soon see- ma$ encodes data as a collection of keyHvalue pairs! 7ut while each container stores its data in a different format- fundamentallyeach container still stores data! 'terators provide a clean- consistent mechanism for accessin& data stored in containers- irrespective of how that data may #e stored! That is- the synta) for lookin& at ve*tor data

Chapter =& ,TL Associative Containers and Iterators

1 1;D 1

with iterators is almost identical to the synta) for e)aminin& set and de[ue data with iterators! This fact is e)tremely important! 8or starters- it implies that once you've learned how to use iterators to traverse any container- you can use them to traverse all containers! ,lso- as you'll see- #ecause iterators can traverse data stored in any container- they can #e used to specify a collection of values in a way that masks how those values are stored #ehind1the1scenes! So what e)actly is an iterator> ,t a hi&h level- an iterator is like a cursor in a te)t editor! ike a cursor- an iterator has a well1defined position inside a container- and can move from one character to the ne)t! ,lso like a cursor- an iterator can #e used to read or write a ran&e of data one element at a time! 't's difficult to &et a &ood feel for how iterators work without havin& a sense of how all the pieces fit to&ether! Therefore- we'll &et our first taste of iterators #y *umpin& head1first into the idiomatic 4loop over the elements of a container6 for loop- then will clarify all of the pieces individually! /ere is a sample piece of code that will traverse the elements of a ve*tor int)- printin& each element out on its own line=
ve*tor int) for (ve*tor itr 1= *out m%Je*tor = "3 ... some initialiUation ... 3" int)44iterator itr = m%Je*tor.begin(); m%Je*tor.end(); !!itr) 3itr endl;

This code is perhaps the densest C++ we've encountered yet- so let's take a few minutes to dissect e)actly what's &oin& on here! The first part of the for loop is the statement
ve*tor int)44iterator itr = m%Je*tor.begin();

This line of code creates an o#*ect of type ve*tor int)44iterator- an iterator varia#le named itr that can traverse a ve*tor int)! "ote that a ve*tor int)44iterator can only iterate over a ve*tor int)! 'f we wanted to iterate over a ve*tor string)- we would need to use a ve*tor string)44iteratorand if we wanted to traverse a set int) we would have to use a set int)44iterator! 0e then initialize the iterator to m%Je*tor.begin()! Jvery ST container class e)ports a mem#er function begin() which yields an iterator pointin& to the first element of that container! 7y initializin& the iterator to m%Je*tor.begin()- we indicate to the C++ compiler that the itr iterator will #e traversin& elements of the container m%Je*tor! 'nside the #ody of the for loop- we have the line
*out 3itr endl;

The stran&e1lookin& entity 3itr is known as an iterator dere$erence and means 4the element #ein& iterated over #y itr!6 ,s itr traverses the elements of the ve*tor- it will proceed from one element to the ne)t in se5uence until all of the elements of the ve*tor have #een visited! ,t each step- the element #ein& iterated over can #e yielded #y prependin& a star to the name of the iterator! 'n the a#ove conte)twe dereference the iterator to yield the current element of m%Je*tor #ein& traversed- then print it out! 0e will discuss the nuances of iterator dereferences in more detail shortly! Feturnin& up to the for loop itself- notice that after each iteration we e)ecute
!!itr;

0hen applied to ints- the !! operator is the increment operatorQ writin& !!m%(nt means 4increment the value of the m%(nt varia#le!6 0hen applied to iterators- the !! operator means 4advance the iterator one step forward!6 7ecause the step condition of the for loop is !!itr- this means that each iteration of the for loop will advance the iterator to the ne)t element in the container- and eventually all elements will #e

1 1;E 1

Chapter =& ,TL Associative Containers and Iterators

visited! Gf course- at some point- we will have visited all of the elements in the ve*tor and will need to stop iteratin&! To detect when an iterator has visited all of the elements- we loop on the condition that
itr 1= m%Je*tor.end();

Jach ST container e)ports a special function called end() that returns an iterator to the element one past the end o$ the container! 8or e)ample- consider the followin& ve*tor=
13 )( ( 1, 31)1 +(++ +0(3

'n this case- the iterators returned #y that ve*tor's begin() and end() functions would point to the followin& locations=
begin34 end34

;
13 )( ( 1, 31)1 +(++ +0(3

"otice that the begin() iterator points to the first element of the ve*tor- while the end() iterator points to the slot one position past the end of the ve*tor! This may seem stran&e at first- #ut is actually an e)cellent desi&n decision! Fecall the for loop from a#ove- which iterates over the elements of a ve*tor! This is reprinted #elow=
for (ve*tor int)44iterator itr = m%Je*tor.begin(); itr 1= m%Je*tor.end(); !!itr) *out 3itr endl;

Compare this to the more traditional loop you're used to- which also iterates over a ve*tor=
for (siUeLt h = 0; h m%Je*tor.siUe(); !!h) *out m%Je*tor[h] endl;

7ecause the ve*tor is zero1inde)ed- if you were to look up the element in the ve*tor at position m%Je*tor.siUe()- you would #e readin& a value not actually contained in the ve*tor! 8or e)ample- in a ve*tor of five elements- the elements are stored at positions 0- 1- ;- @- and A! There is no element at position five- and tryin& to read an element there will result in undefined #ehavior! /owever- in the for loop to iterate over the contents of the ve*tor- we still use the value of m%Je*tor.siUe() as the upper #ound for the iteration- since the loop will cut off as soon as the iteration inde) reaches the value m%Je*tor.siUe()! This is identical to the #ehavior of the end() iterator in the iterator1#ased for loop! m%Je*tor.end() is never a valid iterator- #ut we use it as the loop upper #ound #ecause as soon as the itr iterator reaches m%Je*tor.end() the loop will terminate! Cart of the #eauty of iterators is that the a#ove for loop for iteratin& over the contents of a ve*tor can trivially #e adapted to iterate over *ust a#out any ST container class! 8or instance- if we want to iterate over the contents of a de[ue int)- we could do so as follows=
de[ue int) m%9e[ue = "3 ... some initialiUation ... 3" for (de[ue int)44iterator itr = m%9e[ue.begin(); itr 1= m%9e[ue.end(); !!itr) *out 3itr endl;

Chapter =& ,TL Associative Containers and Iterators

1 1;< 1

This is e4actly the same loop structure- thou&h some of the types have chan&ed Ki!e! we've replaced ve*tor int)44iterator with de[ue int)44iteratorL! /owever- the #ehavior is identical! This loop will traverse the contents of the de[ue in se5uence- printin& each element out as it &oes! Gf course- at this point iterators may seem like a mere curiosity! Sure- we can use them to iterate over a ve*tor or de[ue- #ut we already could do that usin& a more standard for loop! The #eauty of iterators is that they work on any ST container- includin& the set! 'f we have a set of elements we wish to traversewe can do so usin& the followin& synta)=
set int) m%6et = "3 ... some initialiUation ... 3" for (set int)44iterator itr = m%6et.begin(); itr 1= m%6et.end(); !!itr) *out 3itr endl;

,&ain- notice that the structure of the loop is the same as #efore! Gnly the types have chan&ed! Gne crucial detail we've i&nored up to this point is in what order the elements of a set will #e traversed! 0hen usin& the ve*tor or de[ue there is a natural iteration order Kfrom the start of the se5uence to the endL- #ut when usin& the ST set the idea of orderin& is a #it more va&ue! /owever- iteration order over a set is well1specified! 0hen traversin& set elements via an iterator- the elements will #e visited in sorted order- startin& with the smallest element and endin& with the lar&est! This is in part why the ST set can only store elements compara#le usin& the less1than operator= there is no well1defined 4smallest6 or 4#i&&est6 element of a set if the elements cannot #e compared! To see this in action- consider the followin& code snippet=
"3 Generate ten random numbers 3" set int) randomKumbers; for (siUeLt B = 0; B 80; !!B) randomKumbers.insert(rand()); "3 <rint them in sorted order. 3" for (set int)44iterator itr = randomKumbers.begin(); itr 1= randomKumbers.end(); !!itr) *out 3itr endl;

This will print different outputs on each run- since the pro&ram &enerates and stores random num#ers! /owever- the values will always #e in sorted order! 8or e)ample=
13 ( 1, 31)1 )103 *)(( +3(1 ,-3, 10(-- 1(003 1+**)

6+otlig.t on Iterators ,s you *ust saw- there are three ma*or operations on iterators= #ere$erencing the iterator to read a value! Advancing the iterator from one position to the ne)t! Comparing two iterators for e5uality!

'terator dereferencin& is a particularly important operation- and so #efore movin& on we'll take a few minutes to e)plore this in more detail! ,s you've seen so far- iterators can #e used to read the values of a container indirectly! /owever- iterators can also #e used to write the values of a container indirectly as well! 8or e)ample- here is a simple for loop to set all of the elements of a ve*tor int) to 1@D=

1 1@0 1

Chapter =& ,TL Associative Containers and Iterators

for (ve*tor int)44iterator itr = m%Je*tor.begin(); itr 1= m%Je*tor.end(); !!itr) 3itr = 8CD;

This is your first &limpse of the true power of iterators! 7ecause iterators &ive a means for readin& and writin& container elements indirectly- it is possi#le to write functions that operate on data from any container class #y manipulatin& iterators from that container class! These functions are called ,TL algorithms and will #e discussed in more detail ne)t chapter! Up to this point- when workin& with iterators- we have restricted ourselves to ST containers that hold primitive types! That is- we've talked a#out ve*tor int) and set int)- #ut not- say- ve*tor string)! ,ll of the synta) that we have seen so far for containers holdin& primitive types are applica#le to containers holdin& o#*ects! 8or e)ample- this loop will correctly print out all of the strings in a set string)=
for (set string)44iterator itr = m%6et.begin(); itr 1= m%6et.end(); !!itr) *out 3itr endl;

/owever- let's suppose that we want to iterate over a set string) printin& out the lengths of the strings in that set! Unfortunately- the followin& synta) will not work=
for (set string)44iterator itr = m%6et.begin(); itr 1= m%6et.end(); !!itr) *out 3itr.length() endl; // Error" Incorrect synta5!

The pro#lem with this code is that the C++ compiler interprets it as
3(itr.length())

'nstead of
(3itr).length()

That is- the compiler tries to call the none)istent length() function on the iterator and to dereference that- rather than dereferencin& the iterator and then invokin& the length() function on the resultin& value! This is a su#tle yet important difference- so make sure that you take some time to think it throu&h #efore movin& on! To fi) this pro#lem- all ST iterators support and operator called the arrow operator that allows you to invoke mem#er functions on the element currently #ein& iterated over! 8or e)ample- to print out the len&ths of all of the strings in a set string)- the proper synta) is
for (set string)44iterator itr = m%6et.begin(); itr 1= m%6et.end(); !!itr) *out itr-)length() endl;

0e will certainly encounter the arrow operator more as we continue our treatment of the material- so make sure that you understand its usa&e #efore movin& on! Defining 4anges wit. Iterators Fecall for a moment the standard 4loop over a container6 for loop=
set int) m%6et = "3 ... some initialiUation ... 3" for (set int)44iterator itr = m%6et.begin(); itr 1= m%6et.end(); !!itr) *out 3itr endl;

Chapter =& ,TL Associative Containers and Iterators

1 1@1 1

'f you'll notice- this loop is #ounded #y two iterators ( m%6et.begin()- which specifies the first element to iterate over- and m%6et.end()- which defines the element one past the end of the iteration ran&e! This raises an interestin& point a#out the duality of iterators! , single iterator points to a sin&le position in a container class and represents a way to read or write that value indirectly! , pair of iterators defines two positions and conse5uently defines a range of elements! 'n particular- &iven two iterators start and sto$these iterators define the ran&e of elements #e&innin& with start and endin& one position #efore sto$! Usin& mathematical notation- the ran&e of elements defined #y start and sto$ spans Nstart- sto$L! So far- the only ran&es we've considered have #een those of the form N begin()- end()L consistin& of all of the elements of a container! /owever- as we #e&in movin& on to pro&ressively more complicated pro&rams- we will fre5uently work on ran&es that do not span all of a container! 8or e)ample- we mi&ht #e interested in iteratin& over only the first half of a container- or perhaps *ust a slice of elements in a container meetin& some property! 'f you'll recall- the ST set stores its elements in sorted order- a property that &uarantees efficient lookup and insertion! Serendipitously- this allows us to efficiently iterate over a slice out of a set whose values are #ounded #etween some known limits! The set e)ports two functions- lo'erLbound and u$$erLbound- that can #e used to iterate over the elements in a set that are within a certain ran&e! lo'erLbound accepts a value- then returns an iterator to the first element in the set &reater than or e5ual to that value! u$$erLbound similarly accepts a value and returns an iterator to the first element in the set that is strictly &reater than the specified element! 3iven a closed ran&e N lo'er- u$$erO- we can iterate over that ran&e #y usin& lo'erLbound to &et an iterator to the first element no less than lo'er and iteratin& until we reach the value returned #y u$$erLbound- the first element strictly &reater than u$$er! 8or e)ample- the followin& loop iterates over all elements in the set in the ran&e N10- 100O=
set int)44iterator sto$ = m%6et.u$$erLbound(800); for(set int)44iterator itr = m%6et.lo'erLbound(80); itr 1= sto$; !!itr) "3 ... $erform tasBs... 3"

Cart of the #eauty of u$$erLbound and lo'erLbound is that it doesn't matter whether the elements specified as ar&uments to the functions actually e)ist in the set! 8or e)ample- suppose that we run the a#ove for loop on a set containin& all the odd num#ers #etween @ and 1@D! 'n this case- neither 10 nor 100 are contained in the set! /owever- the code will still work correctly! The lo'er[#ound function returns an iterator to the first element at least as large as its ar&ument- and in the set of odd num#ers would return an iterator to the element 11! Similarly- u$$erLbound returns an iterator to the first element strictly greater than its ar&ument- and so would return an iterator to the element 101! 6ummar/ of set The followin& ta#le lists some of the most important set functions! ,&ain- we haven't covered *onst yetso for now it's safe to i&nore it! 0e also haven't covered *onstLiterators- #ut for now you can *ust treat them as iterators that can't write any values!
Constructor= set ;)()
set int) m%6et;

Constructs an empty set! Constructor= set ;)(*onst set ;)? other)


set int) m%=ther6et = m%6et;

Constructs a set that's a copy of another set!

1 1@; 1
Constructor= set ;)((n$ut(terator start,
(n$ut(terator sto$)

Chapter =& ,TL Associative Containers and Iterators


set int) m%6et(m%Je*.begin(), m%Je*.end());

Constructs a set containin& copies of the elements in the ran&e Nstart- sto$L! ,ny duplicates are discarded- and the elements are sorted! "ote that this function accepts iterators from any source!
int numEntries = m%6et.siUe();

siUeLt%$e siUe() *onst

Feturns the num#er of elements contained in the set!


bool em$t%() *onst if(m%6et.em$t%()) { ... #

Feturns whether the set is empty!


void *lear() m%6et.*lear();

Femoves all elements from the set!


iterator begin() *onstLiterator begin() *onst set int)44iterator itr = m%6et.begin();

Feturns an iterator to the start of the set! 7e careful when modifyin& elements in1place!
iterator end() *onstLiterator end() 'hile(itr 1= m%6et.end()) { ... #

Feturns an iterator to the element one past the end of the final element of the set!
$air iterator, bool) insert(*onst ;? value) void insert((n$ut(terator begin, (n$ut(terator end) m%6et.insert(G); m%6et.insert(m%Je*.begin(), m%Je*.end());

The first version inserts the specified value into the set! The return type is a $air containin& an iterator to the element and a bool indicatin& whether the element was inserted successfully KtrueL or if it already e)isted K falseL! The second version inserts the specified ran&e of elements into the set- i&norin& duplicates!
if(m%6et.find(0) 1= m%6et.end()) { ... #

iterator find(*onst ;? element) *onstLiterator find(*onst ;? element) *onst siUeLt%$e *ount(*onst ;? item) *onst

Feturns an iterator to the specified element if it e)ists- and end otherwise!


if(m%6et.*ount(0)) { ... #

Feturns 1 if the specified element is contained in the set- and 0 otherwise!


siUeLt%$e erase(*onst ;? element) void erase(iterator itr); void erase(iterator start, iterator sto$); if(m%6et.erase(0)) {...# "" 0 'as erased m%6et.erase(m%6et.begin()); m%6et.erase(m%6et.begin(), m%6et.end());

Femoves an element from the set! 'n the first version- the specified element is removed if found- and the function returns 1 if the element was removed and 0 if it wasn't in the set! The second version removes the element pointed to #y itr! The final version erases elements in the ran&e Nstart- sto$L!

Chapter =& ,TL Associative Containers and Iterators


iterator lo'erLbound(*onst ;? value) itr = m%6et.lo'erLbound(H);

1 1@@ 1

Feturns an iterator to the first element that is &reater than or e5ual to the specified value! This function is useful for o#tainin& iterators to a ran&e of elements- especially in con*unction with u$$erLbound!
iterator u$$erLbound(*onst ;? value) itr = m%6et.u$$erLbound(800);

Feturns an iterator to the first element that is &reater than the specified value! 7ecause this element must #e strictly &reater than the specified value- you can iterate over a ran&e until the iterator is e5ual to u$$erLbound to o#tain all elements less than or e5ual to the parameter!

A Gseful 3el+er8 pair 0e have *ust finished our treatment of the set and are a#out to move on to one of the ST 's most useful containers- the ma$! /owever- #efore we can cover the ma$ in any detail- we must first make a 5uick diversion to a useful helper class- the $air!
$air is a parameterized class that simply holds two values of ar#itrary type! $air- defined in utilit%),

accepts two template ar&uments and is declared as


$air ;%$e=ne, ;%$e;'o) $air has two fields- named first and se*ond- which store the values of the two elements of the pairQ first is a varia#le of type ;%$e=ne- se*ond of type ;%$e;'o! 8or e)ample- to make a $air that can hold an int and a string- we could write $air int, string) m%<air;

0e could then access the $air's contents as follows


$air int, string) m%<air; m%<air.first = 8CD; m%<air.se*ond = /5!! is a'esome1/;

'n some instances- you will need to create a $air on1the1fly to pass as a parameter Kespecially to the ma$'s insertL! .ou can therefore use the maBeL$air function as follows=
$air int, string) m%<air = maBeL$air(8CD, /string1/);

'nterestin&ly- even thou&h we didn't specify what type of $air to create- the maBeL$air function was a#le to deduce the type of the $air from the types of the elements! This has to do with how C++ handles function templates and we'll e)plore this in more detail later! 4e+resenting 4elations.i+s wit. map Gne of the most important data structures in modern computer pro&rammin& is the map- a way of ta&&in& information with some other piece of data! The inherent idea of a mapping should not come as a surprise to you! ,lmost any entity in the real world has e)tra information associated with it! 8or e)ample- days of the year have associated events- items in your refri&erator have associated e)piration dates- and people you know have associated titles and nicknames! The ma$ ST container mana&es a relationship #etween a

1 1@A 1

Chapter =& ,TL Associative Containers and Iterators

set of *eys and a set of values! 8or e)ample- the keys in the ma$ mi&ht #e email addresses- and the values the names of the people who own those email addresses! ,lternatively- the keys mi&ht #e lon&itudeHlatitude pairs- and the values the name of the city that resides at those coordinates! 2ata in a ma$ is stored in keyHvalue pairs! ike the set- these elements are unordered! ,lso like the set- it is possi#le to 5uery the map for whether a particular *ey e)ists in the ma$ Knote that the check is 4does key I e)ist>6 rather than 4does *eyDvalue pair I e)ist>6L! Unlike the set- however- the ma$ also allows clients to ask 4what is the value associated with key I>6 8or e)ample- in a ma$ from lon&itudeHlatitude pairs to city names- it is possi#le to &ive a properly1constructed pair of coordinates to the map- then &et #ack which city is at the indicated location Kif such a city e)istsL! The ma$ is unusual as an ST container #ecause unlike the ve*tor- de[ue- and set- the ma$ is parameterized over two types- the type of the key and the type of the value! 8or e)ample- to create a ma$ from strings to ints- you would use the synta)
ma$ string, int) m%:a$;

ike the ST set- #ehind the scenes the ma$ is implemented usin& a #alanced #inary tree! This means that the *eys in the ma$ must #e compara#le usin& the less1than operator! Conse5uently- you won't #e a#le to use your own custom stru*ts as keys in an ST ma$! /owever- the values in the map needn't #e compara#le- so it's perfectly fine to map from strings to custom stru*t types! ,&ain- when we cover operator overloadin& later in this te)t- you will see how to store ar#itrary types as keys in an ST ma$! The ma$ supports many different operations- of which four are key= 'nsertin& a new keyHvalue pair! Checkin& whether a particular key e)ists! Mueryin& which value is associated with a &iven key! Femovin& an e)istin& keyHvalue pair!

0e will address each of these in turn! 'n order for a ma$ to #e useful- we will need to populate it with a collection of keyHvalue pairs! There are two ways to insert keyHvalue pairs into the map! The simplest way to insert keyHvalue pairs into a ma$ is to user the element selection operator Ks5uare #racketsL to implicitly add the pair- as shown here=
ma$ string, int) number:a$; number:a$[/Uero/] = 0; number:a$[/one/] = 8; number:a$[/t'o/] = E; "3 ... et*. ... 3"

This code creates a new ma$ from strings to ints! 't then inserts the key /Uero/ which maps to the num#er zero- the key /one/ which maps to the num#er one- etc! "otice that this is a ma*or way in which the ma$ differs from the ve*tor! 'nde)in& into a ve*tor into a none)istent position will cause undefined #ehavior- likely a full pro&ram crash! 'nde)in& into a ma$ into a none)istent key implicitly creates a keyHvalue pair! The s5uare #rackets can #e used #oth to insert new elements into the ma$ and to 5uery the ma$ for the values associated with a particular key! 8or e)ample- assumin& that number:a$ has #een populated as a#ove- consider the followin& code snippet=

Chapter =& ,TL Associative Containers and Iterators


*out *out number:a$[/Uero/] endl; number:a$[/t'o/] 3 number:a$[/t'o/] endl;

1 1@? 1

The output of this pro&ram is


0 )

Gn the first line- we 5uery the number:a$ map for the value associated with the key /Uero/- which is the num#er zero! The second line looks up the value associated with the key /t'o/ and multiplies it with itself! Since /t'o/ maps to the num#er two- the output is four! 7ecause the s5uare #rackets #oth 5uery and create keyHvalue pairs- you should use care when lookin& values up with s5uare #rackets! 8or e)ample- &iven the a#ove num#er map- consider this code=
*out number:a$[/+%UU%/] endl;

7ecause /+%UU%/ is not a key in the ma$- this implicitly creates a keyHvalue pair with /+%UU%/ as the key and zero as the value! K ike the ve*tor and de[ue- the ma$ will zero1initialize any primitive types used as valuesL! Conse5uently- this code will output
0

and will chan&e the number:a$ map so that it now has /+%UU%/ as a key! 'f you want to look up a keyHvalue pair without accidentally addin& a new keyHvalue pair to the ma$- you can use the ma$'s find mem#er function! find takes in a key- then returns an iterator that points to the keyHvalue pair that has the specified key! 'f the key does not e)ist- find returns the ma$'s end() iterator as a sentinel! 8or e)ample=
ma$ string, int)44iterator itr = number:a$.find(/+%UU%/); if (itr == number:a$.end()) *out /We% does not e+ist./ endl; else "3 ... 3"

0hen workin& with an ST ve*tor- de[ue- or set- iterators simply iterated over the contents of the container! That is- a ve*tor int)44iterator can #e dereferenced to yield an int- while a set string)44iterator dereferences to a string! ma$ iterators are sli&htly more complicated #ecause they dereference to a keyHvalue pair! 'n particular- if you have a ma$ We%;%$e, Jalue;%$e)- then the iterator will dereference to a value of type
$air *onst We%;%$e, Jalue;%$e)

This is a $air of an immuta#le key and a muta#le value! 0e have not talked a#out the *onst keyword yet#ut it means that keys in a ma$ cannot #e chan&ed after they are set Kthou&h they can #e removedL! The values associated with a key- on the other hand- can #e modified! 7ecause ma$ iterators dereference to a $air- you can access the keys and values from an iterator as follows=

1 1@6 1

Chapter =& ,TL Associative Containers and Iterators

ma$ string, int)44iterator itr = number:a$.find(/+%UU%/); if (itr == number:a$.end()) *out /We% does not e+ist./ endl; else *out /We% / itr-)first / has value / itr-)se*ond

endl;

That is- to access the key from a ma$ iterator- you use the arrow operator to select the first field of the $air! The value is stored in the se*ond field! This naturally se&ues into the stereotypical 4iterate over the elements of a ma$ loop-6 which looks like this=
for (ma$ string, int)44iterator itr = m%:a$.begin(); itr 1= m%:a$.end(); !!itr) *out itr-)first /4 / itr-)se*ond endl;

0hen iteratin& over a ma$- the keyHvalue pairs will #e produced sorted #y key from lowest to hi&hest! This means that if we were to iterate over the number:a$ map from a#ove printin& out keyHvalue pairs- the output would #e
one" 1 two" ( 6ero" 0

Since the keys are strings which are sorted in alpha#etical order! .ou've now seen how to insert- 5uery- and iterate over keyHvalue pairs! Femovin& keyHvalue pairs from a ma$ is also fairly strai&htforward! To do so- you use the erase function as follows=
m%:a$.erase(/Be%/);

That is- the erase function accepts a *ey- then removes the keyHvalue pair from the ma$ that has that key Kif it e)istsL! ,s with all ST containers- you can remove all keyHvalue pairs from a ma$ usin& the *lear functiondetermine the num#er of keyHvalue pairs usin& the siUe function- etc! There are a few additional operations on a ma$ #eyond these #asic operations- some of which are covered in the ne)t section!
insert and 3ow to A;oid It

,s seen a#ove- you can use the s5uare #rackets operator to insert and update keyHvalue pairs in the ma$! /owever- there is another mechanism for insertin& keyHvalue pairs= insert! ike the set's insert function- you need only specify what to insert- since the ma$- like the set- does not store values in a particular order! /owever- #ecause the ma$ stores elements as keyHvalue pairs- the parameter to the insert function should #e a $air o#*ect containin& the key and the value! 8or e)ample- the followin& code is an alternative means of populatin& the number:a$ map=
ma$ string, int) number:a$; number:a$.insert(maBeL$air(/Uero/, 0)); number:a$.insert(maBeL$air(/one/, 8)); number:a$.insert(maBeL$air(/t'o/, E)); "3 ... 3"

There is one key difference #etween the insert function and the s5uare #rackets! Consider the followin& two code snippets=

Chapter =& ,TL Associative Containers and Iterators


"3 <o$ulate a ma$ using [ ] 3" ma$ string, string) one; one[/5!!/] = /sad/; one[/5!!/] = /ha$$%/; "3 <o$ulate a ma$ using insert 3" ma$ string, string) t'o; t'o.insert(maBeL$air(/5!!/, /sad/)); t'o.insert(maBeL$air(/5!!/, /ha$$%/));

1 1@D 1

'n the first code snippet- we create a ma$ from strings to strings called one! 0e first create a keyHvalue pair mappin& /5!!/ to /sad/- and then overwrite the value associated with /5!!/ to /ha$$%/! ,fter this code e)ecutes- the ma$ will map the key WC++W to the value WhappyW- since in the second line the value was overwritten! 'n the second code snippet- we call insert twice- once insertin& the key /5!!/ with the value /sad/ and once insertin& the key /5!!/ with the value /ha$$%/! 0hen this code e)ecutes- the ma$ will end up holdin& one keyHvalue pair= /5!!/ mappin& to /sad/! 0hy is this the case> ike the ST set- the ma$ stores a uni5ue set of keys! 0hile multiple keys may map to the same valuethere can only #e one keyHvalue pair for any &iven key! 0hen insertin& and updatin& keys with the s5uare #rackets- any updates made to the ma$ are persistentQ writin& code to the effect of m%:a$[Be%] = value ensures that the map contains the key Be% mappin& to value value! /owever- the insert function is not as for&ivin&! 'f you try to insert a keyHvalue pair into a ma$ usin& the insert function and the Be% already e)ists- the ma$ will not insert the keyHvalue pair- nor will it update the value associated with the e)istin& key! To miti&ate this- the ma$'s insert function returns a value of type $air iterator, bool)! The bool value in the $air indicates whether the insert operation succeededQ a result of true means that the keyHvalue pair was added- while a result of false means that the key already e)isted! The iterator returned #y the insert function points to the keyHvalue $air in the ma$! 'f the keyHvalue pair was newly1 added- this iterator points to the newly1inserted value- and if a keyHvalue pair already e)ists the iterator points to the e)istin& keyHvalue pair that prevented the operation from succeedin&! 'f you want to use insert to insert keyHvalue pairs- you can write code to the followin& effect=
"3 ;r% to insert normall%. 3" $air ma$ string, int)44iterator, bool) result = m%:a$.insert(maBeL$air(/6;7/, 8CD)); "3 (f insertion failed, manuall% set the value. 3" if(1result.se*ond) result.first-)se*ond = 8CD;

'n the last line- the e)pression result.first-)se*ond is the value of the e)istin& entry- since result.first yields an iterator pointin& to the entry- so result.first-)se*ond is the value field of the iterator to the entry! ,s you can see- the $air can make for tricky- unintuitive code! 'f insert is so inconvenient- why even #other with it> Usually- you won't- and will use the s5uare #rackets operator instead! /owever- when workin& on an e)istin& code#ase- you are e)tremely likely to run into the insert function- and #ein& aware of its somewhat counterintuitive semantics will save you many hours of frustratin& de#u&&in&!

1 1@E 1 map 6ummar/

Chapter =& ,TL Associative Containers and Iterators

The followin& ta#le summarizes the most important functions on the ST ma$ container! 8eel free to i&nore *onst and *onstLiteratorsQ we haven't covered them yet!
Constructor= ma$ W, J)()
ma$ int, string) m%:a$;

Constructs an empty ma$! Constructor= ma$ W, J)(*onst ma$ W, J)? other) ma$ int, string) m%=ther:a$ = m%:a$; Constructs a ma$ that's a copy of another ma$! Constructor= ma$ W, J)((n$ut(terator start,
(n$ut(terator sto$) ma$ string, int) m%:a$(m%Je*.begin(), m%Je*.end());

Constructs a ma$ containin& copies of the elements in the ran&e Nstart- sto$L! ,ny duplicates are discarded- and the elements are sorted! "ote that this function accepts iterators from any source- #ut they must #e iterators over pairs of keys and values!
siUeLt%$e siUe() *onst int numEntries = m%:a$.siUe();

Feturns the num#er of elements contained in the ma$!


bool em$t%() *onst if(m%:a$.em$t%()) { ... #

Feturns whether the ma$ is empty!


void *lear() m%:a$.*lear();

Femoves all elements from the ma$!


iterator begin() *onstLiterator begin() *onst ma$ int)44iterator itr = m%:a$.begin();

Feturns an iterator to the start of the ma$! Femem#er that iterators iterate over pairs of keys and values!
iterator end() *onstLiterator end() 'hile(itr 1= m%:a$.end()) { ... #

Feturns an iterator to the element one past the end of the final element of the ma$!
$air iterator, bool) insert(*onst $air *onst W, J)? value) void insert((n$ut(terator begin, (n$ut(terator end) m%:a$.insert(maBeL$air(/6;7/, 8CD)); m%:a$.insert(m%Je*.begin(), m%Je*.end());

The first version inserts the specified keyHvalue pair into the ma$! The return type is a $air containin& an iterator to the element and a bool indicatin& whether the element was inserted successfully K trueL or if it already e)isted KfalseL! The second version inserts the specified ran&e of elements into the ma$- i&norin& duplicates!
m%:a$[/6;7/] = /is a'esome/;

J? o$erator[] (*onst W? Be%)

<et#rns the val#e associated with the speci*ied 0ey, i* it e4ists. 2* not, a new 0ey'val#e pair will be created and the val#e initiali=ed to =ero (i* it is a primitive type) or the de*a#lt val#e (*or non)primitive types).

Chapter =& ,TL Associative Containers and Iterators


iterator find(*onst W? element) *onstLiterator find(*onst W? element) *onst if(m%:a$.find(0) 1= m%:a$.end()) { ... #

1 1@< 1

Feturns an iterator to the keyHvalue pair havin& the specified key if it e)ists- and end otherwise!
siUeLt%$e *ount(*onst W? item) *onst if(m%:a$.*ount(0)) { ... #

Feturns 1 if some keyHvalue pair in the ma$ has specified key and 0 otherwise!
siUeLt%$e erase(*onst W? element) void erase(iterator itr); void erase(iterator start, iterator sto$); if(m%:a$ .erase(0)) {...# m%:a$.erase(m%:a$.begin()); m%:a$.erase(m%:a$.begin(), m%:a$.end());

Femoves a keyHvalue pair from the ma$! 'n the first version- the keyHvalue pair havin& the specified key is removed if found- and the function returns 1 if a pair was removed and 0 otherwise! The second version removes the element pointed to #y itr! The final version erases elements in the ran&e Nstart- sto$L!
iterator lo'erLbound(*onst W? value) itr = m%:a$.lo'erLbound(H);

Feturns an iterator to the first keyHvalue pair whose key is &reater than or e5ual to the specified value! This function is useful for o#tainin& iterators to a ran&e of elementsespecially in con*unction with u$$erLbound!
iterator u$$erLbound(*onst W? value) itr = m%:a$.u$$erLbound(800);

Feturns an iterator to the first keyHvalue pair whose key is &reater than the specified value! 7ecause this element must #e strictly &reater than the specified value- you can iterate over a ran&e until the iterator is e5ual to u$$erLbound to o#tain all elements less than or e5ual to the parameter!

)*tended )*am+le8 Ce/word Counter To &ive you a #etter sense for how ma$ and set can #e used in practice- let's #uild a simple application that #rin&s them to&ether= a *eyword counter! C++- like most pro&rammin& lan&ua&es- has a set of reserved words- keywords that have a specific meanin& to the compiler! 8or e)ample- the keywords for the primitive types int and double are reserved words- as are the s'it*h- for- 'hile- do- and if keywords used for control flow! 8or your edification- here's a complete list of the reserved words in C++=
and andLe[ asm auto bitand bitor bool breaB *ase *at*h *har *lass *om$l *onst *onstL*ast *ontinue default delete do double d%nami*L*ast else enum e+$li*it e+$ort e+tern false float for friend goto if inline int long mutable names$a*e ne' not notLe[ o$erator or orLe[ $rivate $rote*ted $ubli* register reinter$retL*ast return short signed siUeof stati* stati*L*ast stru*t s'it*h tem$late this thro' true tr% t%$edef t%$eid t%$ename union unsigned using virtual void volatile '*harLt 'hile +or +orLe[

1 1A0 1

Chapter =& ,TL Associative Containers and Iterators

0e are interested in answerin& the followin& 5uestion= &iven a C++ source file- how many times does each reserved word come up> This #y itself mi&ht not #e particularly enli&htenin&- #ut in some cases it's interestin& to see how often Kor infre5uentlyL the keywords come up in production code! 0e will suppose that we are &iven a file called Be%'ords.t+t containin& all of C++'s reserved words! This file is structured such that every line of the file contains one of C++'s reserved words! /ere's the first few lines= File: keywords.txt
and andLe[ asm auto bitand bitor bool breaB ...

3iven this file- let's write a pro&ram that prompts the user for a filename- loads the file- then reports the fre5uency of each keyword in that file! 8or reada#ility- we'll only print out a report on the keywords that actually occurred in the file! To avoid a ma*or parsin& headache- we'll count keywords wherever they appear- even if they're in comments or contained inside of a strin&! et's #e&in writin& this pro&ram! 0e'll use a top1down approach- #reakin& the task up into smaller su#tasks which we will implement later on! /ere is one possi#le implementation of the main function=
.in*lude iostream) .in*lude string) .in*lude fstream) .in*lude ma$) using names$a*e std; "3 &un*tion4 =$en@ser&ile(ifstream? file6tream); 3 @sage4 =$en@ser&ile(m%6tream); 3 ------------------------------------------------3 <rom$ts the user for a filename until a valid filename 3 is entered, then sets file6tream to read from that file. 3" void =$en@ser&ile(ifstream? file6tream); "3 &un*tion4 Get&ile5ontents(ifstream? file); 3 @sage4 string *ontents = Get&ile5ontents(ifstream? file); 3 ------------------------------------------------3 Ieturns a string *ontaining the *ontents of the file $assed 3 in as a $arameter. 3" string Get&ile5ontents(ifstream? file); "3 &un*tion4 GenerateWe%'ordIe$ort(string te+t); 3 @sage4 ma$ string, siUeLt) Be%'ords = GenerateWe%'ordIe$ort(*ontents); 3 ------------------------------------------------3 Ieturns a ma$ from Be%'ords to the fre[uen*% at 'hi*h those Be%'ords 3 a$$ear in the in$ut te+t string. We%'ords not *ontained in the te+t 'ill 3 not a$$ear in the ma$. 3" ma$ string, siUeLt) GenerateWe%'ordIe$ort(string *ontents);

Chapter =& ,TL Associative Containers and Iterators


int main() { "3 <rom$t the user for a valid file and o$en it as a stream. 3" ifstream in$ut; =$en@ser&ile(in$ut);

1 1A1 1

"3 Generate the re$ort based on the *ontents of the file. 3" ma$ string, siUeLt) re$ort = GenerateWe%'ordIe$ort(Get&ile5ontents(in$ut)); "3 <rint a summar%. 3" for (ma$ string, siUeLt)44iterator itr = re$ort.begin(); itr 1= re$ort.end(); !!itr) *out /We%'ord / itr-)first / o**urred / itr-)se*ond / times./ endl;

The #reakdown of this pro&ram is as follows! 8irst- we prompt the user for a file usin& the =$en@ser&ile function! 0e then o#tain the file contents as a strin& and pass it into GenerateWe%'ordIe$ort- which #uilds us a map from strings of the keywords to siUeLts representin& the fre5uencies! 8inally- we print out the contents of the ma$ in a human1reada#le format! Gf course- we haven't implemented any of the ma*or functions that this pro&ram will use- so this pro&ram won't link- #ut at least it &ives a sense of where the pro&ram is &oin&! et's #e&in implementin& this code #y writin& the =$en@ser&ile function! 8ortunately- we've already written this function last chapter in the ,na*e e)ample! The code for this function is reprinted #elow=
void =$en@ser&ile(ifstream? in$ut) { 'hile(true) { *out /Enter filename4 /; string filename = Get7ine(); in$ut.o$en(filename.*Lstr()); "" 6ee 5ha$ter C for .*Lstr(). if(in$ut.isLo$en()) return; *out /6orr%, ( *anAt find the file / in$ut.*lear(); filename endl;

# #

/ere- the Get7ine() function is from the chapter on streams- and is implemented as
string Get7ine() { string line; getline(in$ut, line); return line; #

et's move on to the ne)t task- readin& the file contents into a string! This can #e done in a few lines of code usin& the streams li#rary! The idea is simple= we'll maintain a string containin& all of the file contents encountered so far- and continuously concatenate on the ne)t line of the file Kwhich we'll read with the streams li#rary's handy getline functionL! This is shown here=

1 1A; 1

Chapter =& ,TL Associative Containers and Iterators

string Get&ile5ontents(ifstream? in$ut) { "3 6tring 'hi*h 'ill hold the file *ontents. 3" string result; "3 Wee$ reading a line of the file until no data remains. 3 string line; 'hile (getline(in$ut, line)) result != line ! /,n/; "" Add the ne'line *hara*ter; getline removes it return result; #

,ll that remains at this point is the GenerateWe%'ordIe$ort function- which ends up #ein& most of the work! The #asic idea #ehind this function is as follows= oad in the list of keywords! 8or each word in the file= 'f it's a keyword- increment the keyword count appropriately! Gtherwise- i&nore it!

0e'll take this one step at a time! 8irst- let's load in the list of keywords! 7ut how should we store those keywords> 0e'll #e iteratin& over words from the user's file- checkin& at each step whether the &iven word is a keyword! This means that we will want to store the keywords in a way where we can easily 5uery whether a strin& is or is not contained in the list of keywords! This is an ideal spot for a set- which is optimized for these operations! 0e can therefore write a function that looks like this to read the reserved words list into a set=
set string) 7oadWe%'ords() { ifstream in$ut(/Be%'ords.t+t/); "" Ko error *he*Bing for brevit%As saBe set string) result; "3 Wee$ reading strings out of the file until 'e *annot read an% more. 3 After reading ea*h string, store it in the result set. 2e *an either 3 use getline or the stream e+tra*tion o$erator here, but the stream 3 e+tra*tion o$erator is a bit more general. 3" string Be%'ord; 'hile (in$ut )) Be%'ord) result.insert(Be%'ord); return result; #

0e now have a way to read in the set of keywords- and can move on to our ne)t task= readin& all of the words out of the file and checkin& whether any of them are reserved words! This is surprisin&ly tricky! 0e are &iven a strin&- a continuous se5uence of characters- and from this strin& want to identify where each 4word6 is! /ow are we to do this> There are many options at our disposal Kwe'll see a heavy1duty way to do this at the end of the chapterL- #ut one particularly ele&ant method is to harness a stringstream! 'f you'll recall- the stringstream class is a stream o#*ect that can #uild and parse strin&s usin& standard stream operations! 8urther recall that when readin& strin& data out of a stream usin& the stream e)traction operator- the read operation will proceed up until it encounters whitespace or the end of the stream! That is- if we had a stream containin& the te)t
;his, dear reader, is a string.

Chapter =& ,TL Associative Containers and Iterators 'f we were to read data from the stream one strin& at a time- we would &et #ack the strin&s
;his, dear reader, is a string.

1 1A@ 1

'n that order! ,s you can see- the input is #roken apart at whitespace #oundaries- rather than word #oundaries! /owever- whenever we encounter a word that does not have punctuation immediately on either side- the strin& is parsed correctly! This su&&ests a particularly clever trick! 0e will modify the full te)t of the file #y replacin& all punctuation characters with whitespace characters! /avin& performed this manipulation- if we parse the file contents usin& a stringstream- each strin& handed #ack to us will #e a complete word! et's write a function- <re$ro*ess6tring- which accepts as input a string #y reference- then replaces all punctuation characters in that strin& with the space character! To help us out- we have the **t%$e) header- which e)ports the is$un*t function! is$un*t takes in a sin&le character- then returns whether or not it is a punctuation character! Unfortunately- is$un*t treats underscores as punctuation- which will cause pro#lems for some reserved words Kfor e)ample- stati*L*astL- and so we'll need to special1case it! The <re$ro*ess6tring function is as follows=
void <re$ro*ess6tring(string? te+t) { for (siUeLt B = 0; B te+t.siUe(); !!B) if (is$un*t(te+t[B]) ?? te+t[B] 1= ALA) "" (f 'e need to *hange it... te+t[B] = A A; "" ... re$la*e it 'ith a s$a*e. #

Com#inin&

this

function

with

GenerateWe%'ordIe$ort=

7oadWe%'ords

&ives

us

this

partial

implementation

of

ma$ string, siUeLt) GenerateWe%'ordIe$ort(string file5ontents) { "3 7oad the set of Be%'ords from disB. 3" set string) Be%'ords = 7oadWe%'ords(); "3 <re$ro*ess the string to allo' for easier $arsing. 3" <re$ro*ess6tring(file5ontents); "3 ... need to fill this in ... 3" #

,ll that's left to do now is tokenize the strin& into individual words- then #uild up a fre5uency map of each keyword! To do this- we'll funnel the preprocessed file contents into a stringstream and use the prototypical stream readin& loop to #reak it apart into individual words! This can #e done as follows=

1 1AA 1

Chapter =& ,TL Associative Containers and Iterators

ma$ string, siUeLt) GenerateWe%'ordIe$ort(string file5ontents) { "3 7oad the set of Be%'ords from disB. 3" set string) Be%'ords = 7oadWe%'ords(); "3 <re$ro*ess the string to allo' for easier $arsing. 3" <re$ro*ess6tring(file5ontents); "3 <o$ulate a stringstream 'ith the file *ontents. 3" stringstream toBeniUer; toBeniUer file5ontents; "3 7oo$ over the 'ords in the file, building u$ the re$ort. 3" ma$ string, siUeLt) result; string 'ord; 'hile (toBeniUer )) 'ord) "3 ... $ro*ess 'ord here ... 3"

"ow that we have a loop for e)tractin& sin&le words from the input- we simply need to check whether each word is a reserved word and- if so- to make a note of it! This is done here=
ma$ string, siUeLt) GenerateWe%'ordIe$ort(string file5ontents) { "3 7oad the set of Be%'ords from disB. 3" set string) Be%'ords = 7oadWe%'ords(); "3 <re$ro*ess the string to allo' for easier $arsing. 3" <re$ro*ess6tring(file5ontents); "3 <o$ulate a stringstream 'ith the file *ontents. 3" stringstream toBeniUer; toBeniUer file5ontents; "3 7oo$ over the 'ords in the file, building u$ the re$ort. 3" ma$ string, siUeLt) result; string 'ord; 'hile (toBeniUer )) 'ord) if (Be%'ords.*ount('ord)) !! result['ord]; return result; #

et's take a closer look at what this code is doin&! 8irst- we check whether the current word is a keyword #y usin& the set's *ount function! 'f so- we increment the count of that keyword in the file #y writin& !!result['ord]! This is a surprisin&ly compact line of code! 'f the keyword has not #een counted #efore- then !!result['ord] will implicitly create a new keyHvalue pair usin& that keyword as the key and initializin& the associated value to zero! The !! operator then kicks in- incrementin& the value #y one! Gtherwise- if the key already e)isted in the ma$- the line of code will retrieve the value- then increment it #y one! Jither way- the count is updated appropriately- and the ma$ will #e populated correctly! 0e now have a workin& implementation of the GenerateWe%'ordIe$ort function- and- com#ined with the rest of the code we've written- we now have a workin& implementation of the keyword countin& pro&ram! ,s an amusin& test- the result of runnin& this pro&ram on itself is as follows=

Chapter =& ,TL Associative Containers and Iterators


7eyword 7eyword 7eyword 7eyword 7eyword 7eyword 7eyword 7eyword 7eyword for occurred 3 times. if occurred 3 times. int occurred 1 times. namespace occurred 1 times. return occurred + times. true occurred 1 times. using occurred 1 times. #oid occurred ( times. while occurred ) times.

1 1A? 1

/ow does this compare to production code> 8or reference- here is the output of the pro&ram when run on the monster source file ns566&rame5onstru*tor.*$$- an 11-000+ line file from the Bozilla 8irefo) source code=P
7eyword 7eyword 7eyword 7eyword 7eyword 7eyword 7eyword 7eyword 7eyword 7eyword 7eyword 7eyword 7eyword 7eyword 7eyword 7eyword 7eyword 7eyword 7eyword 7eyword 7eyword 7eyword 7eyword 7eyword 7eyword 7eyword 7eyword 7eyword 7eyword 7eyword 7eyword 7eyword 7eyword 7eyword 7eyword 7eyword 7eyword 7eyword 7eyword 7eyword 7eyword 7eyword 7eyword 7eyword and occurred (+, times. auto occurred ( times. brea' occurred *, times. case occurred ++ times. catch occurred ( times. char occurred ) times. class occurred 10 times. const occurred 1)- times. continue occurred 11 times. default occurred , times. delete occurred + times. do occurred -- times. else occurred 13* times. enum occurred 1 times. e5plicit occurred ) times. e5tern occurred ) times. false occurred 1( times. float occurred 1* times. for occurred (-( times. friend occurred 3 times. if occurred -,3 times. inline occurred ,+ times. long occurred * times. namespace occurred * times. new occurred *- times. not occurred 1)* times. operator occurred 1 times. or occurred 10, times. pri#ate occurred ( times. protected occurred 1 times. public occurred * times. return occurred )*( times. si6eof occurred 3 times. static occurred 11, times. static8cast occurred (0 times. struct occurred , times. switch occurred ) times. this occurred (0* times. true occurred 1) times. try occurred 10 times. using occurred + times. #irtual occurred 1 times. #oid occurred ,( times. while occurred *3 times.

,s you can see- we have 5uite a lot of C++ &round to cover ( *ust look at all those keywords we haven't covered yetR

P ,s of ,pril 1;- ;010

1 1A6 1 (ulticontainers

Chapter =& ,TL Associative Containers and Iterators

The ST provides two special 4multicontainer6 classes- multima$ and multiset- that act as ma$s and sets e)cept that the values and keys they store are not necessarily uni5ue! That is- a multiset could contain several copies of the same value- while a multima$ mi&ht have duplicate keys associated with different values!
multima$ and multiset Kdeclared in ma$) and set)- respectivelyL have identical synta) to ma$ and set- e)cept that some of the functions work sli&htly differently! 8or e)ample- the *ount function will

return the num#er of copies of an element an a multicontainer- not *ust a #inary zero or one! ,lso- while find will still return an iterator to an element if it e)ists- the element it points to is not &uaranteed to #e the only copy of that element in the multicontainer! 8inally- the erase function will erase all copies of the specified key or element- not *ust the first it encounters!

Gne important distinction #etween the multima$ and re&ular ma$ is the lack of s5uare #rackets! Gn a standard ST ma$- you can use the synta) m%:a$[Be%] = value to add or update a keyHvalue pair! /owever- this operation only makes sense #ecause keys in a ma$ are uni5ue! 0hen writin& m%:a$[Be%]there is only one possi#le keyHvalue pair that could #e meant! /owever- in a multima$ this is not the case#ecause there may #e multiple keyHvalue pairs with the same key! Conse5uently- to insert keyHvalue pairs into a multima$- you will need to use the insert function! 8ortunately- the semantics of the multima$ insert function are much simpler than the ma$'s insert function- since insertions never fail in a multima$! 'f you try to insert a keyHvalue pair into a multima$ for which the key already e)ists in the multima$- the new keyHvalue pair will #e inserted without any fuss! ,fter all- multima$ e)ists to allow sin&le keys to map to multiple valuesR Gne function that's 5uite useful for the multicontainers is e[ualLrange! e[ualLrange returns a $air iterator, iterator) that represents the span of entries e5ual to the specified value! 8or e)ample- &iven a multima$ string, int)- you could use the followin& code to iterate over all entries with key 4ST 6=
"3 6tore the result of the e[ualLrange 3" $air multima$ string, int)44iterator, multima$ string, int)44iterator) m%<air = m%:ulti:a$.e[ualLrange(/6;7/); "3 (terate over it1 3" for(multima$ string, int)44iterator itr = m%<air.first; itr 1= m%<air.se*ond; !!itr) *out itr-)first /4 / itr-)se*ond endl;

The multicontainers are fairly uncommon in practice partially #ecause they can easily #e emulated usin& the re&ular ma$ or set! 8or e)ample- a multima$ string, int) #ehaves similarly to a ma$ string, ve*tor int) ) since #oth act as a map from strings to some num#er of ints! /owever- in many cases the multicontainers are e)actly the tool for the *o#Q we'll see them used later in this chapter! )*tended )*am+le8 2inite Automata Computer science is often e5uated with pro&rammin& and software en&ineerin&! Bany a computer science student has to deal with the occasional 4Gh- you're a computer science ma*orR Can you make me a we#site>6 or 4Computer science- eh> 0hy isn't my 'nternet workin&>6 This is hardly the case and computer science is a much #roader discipline that encompasses many fields- such as artificial intelli&ence- &raphics- and #iocomputation!

Chapter =& ,TL Associative Containers and Iterators

1 1AD 1

Gne particular su#discipline of computer science is computability theory! Since computer science involves so much pro&rammin&- a &ood 5uestion is e)actly what we can command a computer to do! 0hat sorts of pro#lems can we solve> /ow efficiently> 0hat pro#lems can)t we solve and why not> Bany of the most important results in computer science- such as the undecida#ility of the haltin& pro#lem- arise from computa#ility theory! 7ut how e)actly can we determine what can #e computed with a computer> Bodern computers are phenomenally comple) machines! 8or e)ample- here is a hi&h1level model of the chipset for a mo#ile 'ntel processor= N'ntelO

Bodelin& each of these components is e)ceptionally tricky- and tryin& to devise any sort of proof a#out the capa#ilities of such a machine would #e all #ut impossi#le! 'nstead- one approach is to work with automata- a#stract mathematical models of computin& machines Kthe sin&ular of automata is the plural of automatonL! Some types of automata are realiza#le in the physical world Kfor e)ample- deterministic and nondeterministic finite automata- as you'll see #elowL- while others are not! 8or e)ample- the Turing machine- which computer scientists use as an overappro)imation of modern computers- re5uires infinite stora&e space- as does the weaker pushdown automaton! ,lthou&h much of automata theory is purely theoretical- many automata have direct applications to software en&ineerin&! 8or e)ample- most production compilers simulate two particular types of automata Kcalled pushdown automata and nondeterministic $inite automataL to analyze and convert source code into a form reada#le #y the compiler's semantic analyzer and code &enerator! Fe&ular e)pression matcherswhich search throu&h te)t strin&s in search of patterned input- are also fre5uently implemented usin& an automaton called a deterministic $inite automaton! 'n this e)tended e)ample- we will introduce two types of automata- deterministic $inite automata and nondeterministic $inite automata- then e)plore how to represent them in C++! 0e'll also e)plore how these automata can #e used to simplify difficult strin&1matchin& pro#lems!

1 1AE 1 Deterministic 2inite Automata

Chapter =& ,TL Associative Containers and Iterators

Cerhaps the simplest form of an automaton is a deterministic $inite automaton- or 28,! ,t a hi&h1level- a 28, is similar to a flowchart ( it has a collection of states *oined #y various transitions that represent how the 28, should react to a &iven input! 8or e)ample- consider the followin& 28,= This 28, has four states- la#eled 50- 51- 5;- and 5@- and a set of la#eled transitions #etween those states! 8or e)ample- the state 50 has a transition la#eled - to 51 and a transition la#eled 1 to 5;! Some states have transitions to themselvesQ for e)ample- 5 ; transitions to itself on a 1- while 5@ transitions to itself on either a - or 1! "ote that as shorthand- the transition la#eled -I 1 indicates two different transitions- one la#eled with a - and one la#eled with a 1! The 28, has a desi&nated state state- in this case 5 0- which is indicated #y the arrow la#eled start! "otice that the state 5@ has two rin&s around it! This indicates that 5 @ is an accepting state- which will have si&nificance in a moment when we discuss how the 28, processes input! Since all of the transitions in this 28, are la#eled either - or 1- this 28, is said to have an alphabet of ]-1^! , 28, can use any nonempty set of sym#ols as an alpha#etQ for e)ample- the atin or 3reek alpha#ets are perfectly accepta#le for use as alpha#ets in a 28,- as is the set of inte&ers #etween A; and 1@D! 7y definition- every state in a 28, is re5uired to have a transition for each sym#ol in its alpha#et! 8or e)ample- in the a#ove 28,- each state has e)actly two transitions- one la#eled with a - and the other with a 1! "otice that state 5 @ has only one transition e)plicitly drawn- #ut #ecause the transition is la#eled with two sym#ols we treat it as two different transitions! The 28, is a simple computin& machine that accepts as input a strin& of characters formed from its alpha#et- processes the strin&- and then halts #y either accepting the strin& or re!ecting it! 'n essence- the 28, is a device for discriminatin& #etween two types of input ( input for which some criterion is true and input for which it is false! The 28, starts in its desi&nated start state- then processes its input character1 #y1character #y transitionin& from its current state to the state indicated #y the transition! Gnce the 28, has finished consumin& its input- it accepts the strin& if it ends in an acceptin& stateQ otherwise it re*ects the input! To see e)actly how a 28, processes input- let us consider the a#ove 28, simulated on the input --11! 'nitially- we #e&in in the start state- as shown here=

start

%0 1 %! 1

0 % 1

%" 0, 1

Since the first character of our strin& is a -- we follow the transition to state 51- as shown here=

Chapter =& ,TL Associative Containers and Iterators

1 1A< 1

start

%0 1 %! 1

0 % 1

%" 0, 1

The second character of input is also a -- so we follow the transition la#eled with a - and end up #ack in state 51- leavin& us in this state=

start

%0 1 %! 1

0 % 1

%" 0, 1

"e)t- we consume the ne)t input character- a 1- which causes us to follow the transition la#eled 1 to state 5@= The final character of input is also a 1- so we follow the transition la#eled 1 and end #ack up in 5@=

start

%0 1 %! 1

0 % 1

%" 0, 1

0e are now done with our input- and since we have ended in an acceptin& state- the 28, accepts this input! 0e can similarly consider the action of this 28, on the strin& 111! 'nitially the machine will start in state 50- then transition to state 5; on the first input! The ne)t two inputs each cause the 28, to transition #ack to state 5;- so once the input is e)hausted the 28, ends in state 5 ;- so the 28, re*ects the input! 0e will not prove it here- #ut this 28, accepts all strin&s that have at least one - and at least one 1! Two important details re&ardin& 28,s deserve some mention! 8irst- it is possi#le for a 28, to have multiple acceptin& states- as is the case in this 28,= ,s with the previous 28,- this 28, has four states- #ut notice that three of them are marked as acceptin&! This leads into the second important detail re&ardin& 28,s ( the 28, only accepts its input if the 28, ends in an acceptin& state when it runs out o$ input ! Simply transitionin& into an acceptin& state does not cause the 28, to accept! 8or e)ample- consider the effect of runnin& this 28, on the input -1-1! 0e #e&in in the start state- as shown here=

1 1?0 1

Chapter =& ,TL Associative Containers and Iterators

0e first consume a -- sendin& us to state 51=

&ta rt

0 %0 0 % 1 0 0 %" 1

1 %!

"e)t- we read a 1- sendin& us to state 5@=

&ta rt

0 %0 0 % 1 0 0 %" 1

1 %!

The ne)t input is a -- sendin& us to 5;= 8inally- we read in a 1- sendin& us #ack to 50=

&ta rt

0 %0 0 % 1 0 0 %" 1

1 %!

Since we are out of input and are not in an acceptin& state- this 28, re*ects its input- even thou&h we transitioned throu&h every sin&le acceptin& state! 'f you want a fun challen&e- convince yourself that this 28, accepts all strin&s that contain an odd num#er of -s or an odd num#er of 1s Kinclusive GFL! 4e+resenting a D2A

Chapter =& ,TL Associative Containers and Iterators

1 1?1 1

, 28, is a simple model of computation that can easily #e implemented in software or hardware! 8or any 28,- we need to store five pieces of information=P 1. 2. 3. 4. . The set of states used #y the 28,! The 28,'s alpha#et! The start state! The state transitions! The set of acceptin& states!

Gf these five- the one that deserves the most attention is the fourth- the set of state transitions! Tisuallywe have displayed these transitions as arrows #etween circles in the &raph! /owever- another way to treat state transitions is as a ta#le with states alon& one a)is and sym#ols of the alpha#et alon& the other! 8or e)ample- here is a transition ta#le for the 28, descri#ed a#ove= State 50 51 5; 5@ 51 50 5@ 5; 1 5; 5@ 50 51

To determine the state to transition to &iven a current state and an input sym#ol- we look up the row for the current state- then look at the state specified in the column for the current input! 'f we want to implement a pro&ram that simulates a 28,- we can represent almost all of the necessary information simply #y storin& the transition ta#le! The two a)es encode all of the states and alpha#et sym#ols- and the entries of the ta#le represent the transitions! The information not stored in this ta#le is the set of acceptin& states and the desi&nated start state- so provided that we #undle this information with the ta#le we have a full description of a 28,! To concretely model a 28, usin& the ST - we must think of an optimal way to model the transition ta#le! Since transitions are associated with pairs of states and sym#ols- one option would #e to model the ta#le as an ST ma$ mappin& a state1sym#ol pair to a new state! 'f we represent each sym#ol as a *har and each state as an int Ki!e! 50 is 0- 51 is 1- etc!L- this leads to a state transition ta#le stored as a ma$ $air int, *har), int)! 'f we also track the set of acceptin& states as a set int)- we can encode a 28, as follows=
stru*t 9&A { ma$ $air int, *har), int) transitions; set int) a**e$ting6tates; int start6tate; #;

8or the purposes of this e)ample- assume that we have a function which fills this 9&A struct will relevant data! "ow- let's think a#out how we mi&ht &o a#out simulatin& the 28,! To do this- we'll write a function 6imulate9&A which accepts as input a 9&A stru*t and a strin& representin& the input- simulates the 28, when run on the &iven input- and then returns whether the input was accepted! 0e'll #e&in with the followin&=
bool 6imulate9&A(9&A? d, string in$ut) { P 'n formal literature- a 28, is often characterized as a 5uintuple KM- >- 50- ?- 8L of the states- alpha#et- start statetransition ta#le- and set of acceptin& states- respectively! Take CS1?A if you're interested in learnin& more a#out these wonderful automata- or CS1A@ if you're interested in their applications!

1 1?; 1
# "3 ... 3"

Chapter =& ,TL Associative Containers and Iterators

0e need to maintain the state we're currently in- which we can do #y storin& it in an int! 0e'll initialize the current state to the startin& state- as shown here=
bool 6imulate9&A(9&A? d, string in$ut) { int *urr6tate = d.start6tate; "3 ... 3" #

"ow- we need to iterate over the strin&- followin& transitions from state to state! Since the transition ta#le is represented as a ma$ from $air int, *har)s- we can look up the ne)t state #y usin& maBeL$air to construct a pair of the current state and the ne)t input- then lookin& up its correspondin& value in the ma$! ,s a simplifyin& assumption- we'll assume that the input strin& is composed only of characters from the 28,'s alpha#et! This leads to the followin& code=
bool 6imulate9&A(9&A? d, string in$ut) { int *urr6tate = d.start6tate; for(string44iterator itr = in$ut.begin(); itr 1= in$ut.end(); !!itr) *urr6tate = d.transitions[maBeL$air(*urr6tate, 3itr)]; "3 ... 3" #

.ou may #e wonderin& how we're iteratin& over the contents of a string usin& iterators! Surprisin&ly- the string is specially desi&ned like the ST container classes- and so it's possi#le to use all of the iterator tricks you've learned on the ST containers directly on the string! Gnce we've consumed all the input- we need to check whether we ended in an acceptin& state! 0e can do this #y lookin& up whether the *urr6tate varia#le is contained in the a**e$ting6tates set in the 9&A struct- as shown here=

Chapter =& ,TL Associative Containers and Iterators


bool 6imulate9&A(9&A? d, string in$ut) { int *urr6tate = d.start6tate; for(string44iterator itr = in$ut.begin(); itr 1= in$ut.end(); !!itr) *urr6tate = d.transitions[maBeL$air(*urr6tate, 3itr)]; return d.a**e$ting6tates.find(*urr6tate) 1= d.a**e$ting6tates.end(); #

1 1?@ 1

This function is remarka#ly simple #ut correctly simulates the 28, run on some input! ,s you'll see in the ne)t section on applications of 28,s- the simplicity of this implementation lets us harness 28,s to solve a suite of pro#lems surprisin&ly efficiently! A++lications of D2As The C++ string class e)ports a handful of searchin& functions Kfind- findLfirstLoffindLlastLnotLof- etc!L that are useful for locatin& specific strin&s or characters! /owever- it's surprisin&ly tricky to search strin&s for specific patterns of characters! The canonical e)ample is searchin& for email addresses in a strin& of te)t! ,ll email addresses have the same structure ( a name field followed #y an at si&n KXL and a domain name! 8or e)ample- htiek9cs!stanford!edu and this!is!not!my!real!address9e)ample!com are valid email addresses! 'n &eneral- we can specify the formattin& of an email address as follows=P The name field- which consists of nonempty alphanumeric strin&s separated #y periods! Ceriods can only occur #etween alphanumeric strin&s- never #efore or after! Thus hello!world9e)ample!com and cpp!is!really!cool9e)ample!com are le&al #ut !oops9e)ample!comoops!9e)ample!com- and oops!!oops9e)ample!com are not! The host field- which is structured similarly to the a#ove e)cept that there must #e at least two se5uences separated #y a dot!

"ow- suppose that we want to determine whether a strin& is a valid email address! Usin& the searchin& functions e)ported #y the string class this would #e difficult- #ut the pro#lem is easily solved usin& a 28,! 'n particular- we can desi&n a 28, over a suita#le alpha#et that accepts a strin& if and only if the strin& has the a#ove formattin&! The first 5uestion to consider is what alpha#et this 28, should #e over! 0hile we could potentially have the 28, operate over the entire ,SC'' alpha#et- it's easier if we instead &roup to&ether related characters and use a simplified alpha#et! 8or e)ample- since email addresses don't distin&uish #etween letters and num#ers- we can have a sin&le sym#ol in our alpha#et that encodes any alphanumeric character! 0e would need to maintain the period and at1si&n in the alpha#et since they have semantic si&nificance! Thus our alpha#et will #e ]a- .- 9^- where a represents alphanumeric characters- . is the period character- and 9 is an at1si&n! 3iven this alpha#et- we can represent all email addresses usin& the followin& 28,=

P This is a simplified version of the formattin& of email addresses! 8or a full specification- refer to F8Cs ?@;1 and ?@;;!

1 1?A 1

Chapter =& ,TL Associative Containers and Iterators


a0 .0 9 .0 9

%( %!
.
&tart

.0 9
.0

%'
.0 9 9 . a
9

%0
a a

%"

%#

. a

%$

This 28, is considera#ly trickier than the ones we've encountered previously- so let's take some time to &o over what's happenin& here! The machine starts in state 5 0- which represents the #e&innin& of input! Since all email addresses have to have a nonempty name field- this state represents the #e&innin& of the first strin& in the name! The first character of an email address must #e an alphanumeric character- which if read in state 50 cause us to transition to state 5 1! States 51 and 5; check that the start of the input is somethin& appropriately formed from alphanumeric characters separated #y periods! Feadin& an alphanumeric character while in state 5 1 keeps the machine there Kthis represents a continuation of the current wordL- and readin& a dot transitions the machine to 5 ;! 'n 5;- readin& anythin& other than an alphanumeric character puts the machine into the 4trap state-6 state 5 D- which represents that the input is invalid! "ote that once the machine reaches state 5 D no input can &et the machine out of that state and that 5D isn't acceptin&! Thus any input that &ets the machine into state 5 D will #e re*ected! State 5@ represents the state of havin& read the at1si&n in the email address! /ere readin& anythin& other than an alphanumeric character causes the machine to enter the trap state! States 5A and 5? are desi&ned to help catch the name of the destination server! ike 5 1- 5A represents a state where we're readin& a 4word6 of alphanumeric characters and 5? is the state transitioned to on a dot! 8inally- state 56 represents the state where we've read at least one word followed #y a dot- which is the acceptin& state! ,s an e)ercise- trace the action of this machine on the inputs valid!address9email!com and invalid9not!com9ouch! "ow- how can we use this 28, in code> Suppose that we have some way to populate a 9&A struct with the information for this 28,! Then we could check if a strin& contains an email address #y convertin& each character in the strin& into its appropriate character in the 28, alpha#et- then simulatin& the 28, on the input! 'f the 28, re*ects the input or the strin& contains an invalid character- we can si&nal that the strin& is invalid- #ut otherwise the strin& is a valid email address! This can #e implemented as follows=

Chapter =& ,TL Associative Containers and Iterators


bool (sEmailAddress(string in$ut) { 9&A email5he*Ber = 7oadEmail9&A(); "" (m$lemented else'here

1 1?? 1

"3 ;ransform the string one *hara*ter at a time. 3" for(string44iterator itr = in$ut.begin(); itr 1= in$ut.end(); !!itr) { "3 isalnum is e+$orted b% **t%$e) and *he*Bs if the in$ut is an 3 al$hanumeri* *hara*ter. 3" if(isalnum(3itr)) 3itr = AaA; "3 (f 'e donAt have al$hanumeri* data, 'e have to be a dot or at-sign 3 or the in$ut is invalid. 3" else if(3itr 1= A.A ?? 3itr 1= AXA) return false; # return 6imulate9&A(email5he*Ber, in$ut);

This code is remarka#ly concise- and provided that we have an implementation of 7oadEmail9&A the function will work correctly! ''ve left out the implementation of 7oadEmail9&A since it's somewhat tedious- #ut if you're determined to see that this actually works feel free to try your hand at implementin& it! @ondeterministic 2inite Automata , &eneralization of the 28, is the nondeterministic $inite automaton- or "8,! ,t a hi&h level- 28,s and "8,s are 5uite similar ( they #oth consist of a set of states connected #y la#eled transitions- of which some states are desi&nated as acceptin& and others as re*ectin&! /owever- "8,s differ from 28,s in that a state in an "8, can have any num#er of transitions on a &iven input- includin& zero! 8or e)ample- consider the followin& "8,= /ere- the start state is 50 and acceptin& states are 5; and 5A! "otice that the start state 50 has two transitions on - ( one to 51 and one to itself ( and two transitions on 1! ,lso- note that 5@ has no defined transitions on -- and states 5; and 5A have no transitions at all! There are several ways to interpret a state havin& multiple transitions! The first is to view the automaton as choosin& one of the paths nondeterministically Khence the nameL- then acceptin& the input if some set of choices results in the automaton endin& in an acceptin& state! ,nother- more intuitive way for modelin& multiple transitions is to view the "8, as #ein& in several different states simultaneously- at each step followin& every transition with the appropriate la#el in each of its current states! To see this- let's consider what happens when we run the a#ove "8, on the input --11! ,s with a 28,- we #e&in in the start stateas shown here=

&t a

rt

% 0 %0 1 %"

%!

0, 1

%#

0e now process the first character of input K -L and find that there are two transitions to follow ( the first to 50 and the second to 51! The "8, thus ends up in #oth of these states simultaneously- as shown here=

1 1?6 1

Chapter =& ,TL Associative Containers and Iterators

&t a

rt

% 0 %0 1 %"

%!

0, 1

%#

"e)t- we process the second character K-L! 8rom state 50- we transition into 50 and 51- and from state 51 we transition into 5;! 0e thus end up in states 50- 51- and 5;- as shown here=

&t a

rt

% 0 %0 1 %"

%!

0, 1

%#

0e now process the third character of input- which is a 1! 8rom state 50 we transition to states 5 0 and 5@! 0e are also currently in states 5 1 and 5;- #ut neither of these states has a transition on a 1! 0hen this happens- we simply drop the states from the set of current states! Conse5uently- we end up in states 5 0 and 5@- leavin& us in the followin& confi&uration=

&t a

rt

% 0 %0 1 %"

%!

0, 1

%#

8inally- we process the last character- a 1! State 50 transitions to 50 and 51- and state 51 transitions to state 5A! 0e thus end up in this final confi&uration=

&t a

rt

% 0 %0 1 %"

%!

0, 1

%#

Since the "8, ends in a confi&uration where at least one of the active states is an acceptin& state K5 AL- the "8, accepts this input! ,&ain as an e)ercise- you mi&ht want to convince yourself that this "8, accepts all and only the strin&s that end in either -- or 11! Im+lementing an @2A Fecall from a#ove the definition of the 9&A struct=
stru*t 9&A { ma$ $air int, *har), int) transitions; set int) a**e$ting6tates; int start6tate; #;

Chapter =& ,TL Associative Containers and Iterators

1 1?D 1

/ere- the transition ta#le was encoded as a ma$ $air int, *har), int) since for every com#ination of a state and an alpha#et sym#ol there was e)actly one transition! To &eneralize this to represent an "8,we need to #e a#le to associate an ar#itrary num#er of possi#le transitions! This is an ideal spot for an ST multima$- which allows for duplicate keyHvalue pairs! This leaves us with the followin& definition for an "8, type=
stru*t K&A { multima$ $air int, *har), int) transitions; set int) a**e$ting6tates; int start6tate; #;

/ow would we &o a#out simulatin& this "8,> ,t any &iven time- we need to track the set of states that we are currently in- and on each input need to transition from the current set of states to some other set of states! , natural representation of the current set of states is Khopefully unsurprisin&lyL as a set int)! 'nitially- we start with this set of states *ust containin& the start state! This is shown here=
bool 6imulateK&A(K&A? nfa, string in$ut) { "3 ;ra*B our set of states. 2e begin in the start state. 3" set int) *urr6tates; *urr6tates.insert(nfa.start6tate); "3 ... 3" #

"e)t- we need to iterate over the strin& we've received as input- followin& transitions where appropriate! This at least re5uires a simple for loop- which we'll write here=
bool 6imulateK&A(K&A? nfa, string in$ut) { "3 ;ra*B our set of states. 2e begin in the start state. 3" set int) *urr6tates; *urr6tates.insert(nfa.start6tate); for(string44iterator itr = in$ut.begin(); itr 1= in$ut.end(); !!itr) { "3 ... 3" # "3 ... 3" #

"ow- for each character of input in the strin&- we need to compute the set of ne)t states Kif anyL to which we should transition! To simplify the implementation of this function- we'll create a second set int) correspondin& to the ne)t set of states the machine will #e in! This eliminates pro#lems caused #y addin& elements to our set of states as we're iteratin& over the set and updatin& it! 0e thus have
bool 6imulateK&A(K&A? nfa, string in$ut) { "3 ;ra*B our set of states. 2e begin in the start state. 3" set int) *urr6tates; *urr6tates.insert(nfa.start6tate); for(string44iterator itr = in$ut.begin(); itr 1= in$ut.end(); !!itr) { set int) ne+t6tates; "3 ... 3" #

1 1?E 1
# "3 ... 3"

Chapter =& ,TL Associative Containers and Iterators

"ow that we have space to put the ne)t set of machine states- we need to fi&ure out what states to transition to! Since we may #e in multiple different states- we need to iterate over the set of current statescomputin& which states they transition into! This is shown here=
bool 6imulateK&A(K&A? nfa, string in$ut) { "3 ;ra*B our set of states. 2e begin in the start state. 3" set int) *urr6tates; *urr6tates.insert(nfa.start6tate); for(string44iterator itr = in$ut.begin(); itr 1= in$ut.end(); !!itr) { set int) ne+t6tates; for(set int)44iterator state = *urr6tates.begin(); state 1= *urr6tates.end(); !!state) { "3 ... 3" # # "3 ... 3" #

3iven the state #ein& iterated over #y state and the current input character- we now want to transition to each state indicated #y the multima$ stored in the K&A struct! 'f you'll recall- the ST multima$ e)ports a function called e[ualLrange which returns a $air of iterators into the multima$ that delineate the ran&e of elements with the specified key! This function is e)actly what we need to determine the set of new states we'll #e enterin& for each &iven state ( we simply 5uery the multima$ for all elements whose key is the pair of the specified state and the current input- then add all of the destination states to our ne)t set of states! This is shown here=

Chapter =& ,TL Associative Containers and Iterators


bool 6imulateK&A(K&A? nfa, string in$ut) { "3 ;ra*B our set of states. 2e begin in the start state. 3" set int) *urr6tates; *urr6tates.insert(nfa.start6tate);

1 1?< 1

for(string44iterator itr = in$ut.begin(); itr 1= in$ut.end(); !!itr) { set int) ne+t6tates; for(set int)44iterator state = *urr6tates.begin(); state 1= *urr6tates.end(); !!state) { "3 Get all states that 'e transition to from this *urrent state. 3" $air multima$ $air int, *har), int)44iterator, multima$ $air int, *har), int)44iterator) transitions = nfa.transitions.e[ualLrange(maBeL$air(3state, 3itr)); "3 Add these ne' states to the ne+t6tates set. 3" for(; transitions.first 1= transitions.se*ond; !!transitions.first) "3 transitions.first is the *urrent iterator, and its se*ond 3 field is the value (ne' state) in the 6;7 multima$. 3" ne+t6tates.insert(transitions.first-)se*ond); # # #

"3 ... 3"

8inally- once we've consumed all input- we need to check whether the set of states contains any states that are also in the set of acceptin& states! 0e can do this #y simply iteratin& over the set of current states- then checkin& if any of them are in the acceptin& set! This is shown here and completes the implementation of the function=

1 160 1

Chapter =& ,TL Associative Containers and Iterators

bool 6imulateK&A(K&A? nfa, string in$ut) { "3 ;ra*B our set of states. 2e begin in the start state. 3" set int) *urr6tates; *urr6tates.insert(nfa.start6tate); for(string44iterator itr = in$ut.begin(); itr 1= in$ut.end(); !!itr) { set int) ne+t6tates; for(set int)44iterator state = *urr6tates.begin(); state 1= *urr6tates.end(); !!state) { "3 Get all states that 'e transition to from this *urrent state. 3" $air multima$ $air int, *har), int)44iterator, multima$ $air int, *har), int)44iterator) transitions = nfa.transitions.e[ualLrange(maBeL$air(3state, 3itr)); "3 Add these ne' states to the ne+t6tates set. 3" for(; transitions.first 1= transitions.se*ond; !!transitions.first) "3 transitions.first is the *urrent iterator, and its se*ond 3 field is the value (ne' state) in the 6;7 multima$. 3" ne+t6tates.insert(transitions.first-)se*ond); # #

for(set int)44iterator itr = *urr6tates.begin(); itr 1= *urr6tates.end(); !!itr) if(nfa.a**e$ting6tates.*ount(3itr)) return true; return false;

Compare this function to the implementation of the 28, simulation! There is su#stantially more code here- since we have to track multiple different states rather than *ust a sin&le state! /owever- this e)tra comple)ity is counter#alanced #y the simplicity of desi&nin& "8,s compared to 28,s! 7uildin& a 28, to match a &iven pattern can #e much trickier than #uildin& an e5uivalent "8, #ecause it's difficult to model 4&uessin&6 #ehavior with a 28,! /owever- #oth functions are a useful addition to your pro&rammin& arsenal- so it's &ood to see how they're implemented! (ore to )*+lore 'n this chapter we covered ma$ and set- which com#ined with ve*tor and de[ue are the most commonly1 used ST containers! /owever- there are several others we didn't cover- a few of which mi&ht #e worth lookin& into! /ere are some topics you mi&ht want to read up on= 1. list= ve*tor and de[ue are se5uential containers that mimic #uilt1in arrays! The list containerhowever- models a se5uence of elements without indices! list supports several nifty operationssuch as mer&in&- sortin&- and splicin&- and has 5uick insertions at almost any point! 'f you're plannin& on usin& a linked list for an operation- the list container is perfect for you! 2. T.e Boost Containers= The 7oost C++ i#raries are a collection of functions and classes developed to au&ment C++'s native li#rary support! 7oost offers several new container classes that mi&ht #e worth lookin& into! 8or e)ample- multiLarra% is a container class that acts as a Grid in any num#er of dimensions! ,lso- the unorderedLset and unorderedLma$ act as replacements to the set and ma$ that use hashin& instead of tree structures to store their data! 'f you're interested in e)plorin& these containers- head on over to www!#oost!or&!

Chapter =& ,TL Associative Containers and Iterators !ractice !roblems 1. /ow do you check whether an element is contained in an ST set>

1 161 1

2. 0hat is the restriction on what types can #e stored in an ST set> 2o the ve*tor or de[ue have this restriction> 3. /ow do you insert an element into a set> /ow do you remove an element from a set> 4. /ow many copies of a sin&le element can e)ist in a set> /ow a#out a multiset> . /ow do you iterate over the contents of a set> !. /ow do you check whether a key is contained in an ST ma$> $. ist two ways that you can insert keyHvalue pairs into an ST ma$!
ma$ usin&

6. 0hat happens if you look up the value associated with a none)istent key in an ST s5uare #rackets> 0hat if you use the find function>

7. Fecall that when iteratin& over the contents of an ST multiset- the elements will #e visited in sorted order! Usin& this property- rewrite the pro&ram from last chapter that reads a list of num#ers from the user- then prints them in sorted order! 0hy is it necessary to use a multiset instead of a re&ular set> 10. The union of two sets is the collection of elements contained in at least one of the sets! 8or e)ample- the union of ]1- ;- @- ?- E^ and ];- @- ?- D- 11^ is ]1- ;- @- ?- D- E- 11^! 0rite a function @nion which takes in two set int)s and returns their union! 11. The intersection of two sets is the collection of elements contained in both of the sets! 8or e)ample- the intersection of ]1- ;- @- ?- E^ and ];- @- ?- D- 11^ is ];- @- ?^! 0rite a function (nterse*tion that takes in two set int)s and returns their intersection! 12. Jarlier in this chapter- we wrote a pro&ram that rolled dice until the same num#er was rolled twice- then printed out the num#er of rolls made! Fewrite this pro&ram so that the same num#er must #e rolled three times #efore the process terminates! /ow many times do you e)pect this process to take when rollin& twenty1sided dice> 5+int& you will probably want to switch $rom using a set to using a multiset Also, remember the di$$erence between the set)s count $unction and the multiset)s count $unction6 13. ,s mentioned in this chapter- you can use a com#ination of lo'erLbound and u$$erLbound to iterate over elements in the closed interval Nmin- ma)O! 0hat com#ination of these two functions could you use to iterate over the interval Nmin- ma)L> 0hat a#out Kmin- ma)O and Kmin- ma)L> 14. 0rite a function Kumber9u$li*ateEntries that accepts a ma$ string, string) and returns the num#er of duplicate values in the ma$ Kthat is- the num#er of keyHvalue pairs in the map with the same valueL!

1 16; 1

Chapter =& ,TL Associative Containers and Iterators

1 . 0rite a function (nvert:a$ that accepts as input a ma$ string, string) and returns a multima$ string, string) where each pair Kkey- valueL in the source map is represented #y Kvalue- keyL in the &enerated multima$! 0hy is it necessary to use a multima$ here> /ow could you use the Kumber9u$li*ateEntries function from the previous 5uestion to determine whether it is possi#le to invert the ma$ into another ma$> 1!. Suppose that we have two ma$ string, string)s called one and t'o! 0e can define the composition of one and t'o Kdenoted t'o ] oneL as follows= for any strin& r- if one[r] is s and t'o[s] is t- then Kt'o ] oneL[r] = t! That is- lookin& up an element + in the composition of the maps is e5uivalent to lookin& up the value associated with + in one and then lookin& up its associated value in t'o! 'f one does not contain r as a key or if one[r] is not a key in t'o- then Kt'o ] oneL[r] is undefined! 0rite a function 5om$ose:a$s that takes in two ma$ string, string)s and returns a ma$ string, string) containin& their composition! 1$. KChallen&e pro#lemRL 0rite a function <rint:at*hing<refi+es that accepts a set string) and a string containin& a prefi) and prints out all of the entries of the set that #e&in with that prefi)! .our function should only iterate over the entires it finally prints out! .ou can assume the prefi) is nonempty- consists only of alphanumeric characters- and should treat prefi)es case1sensitively! 5+int& In a set&string(, strings are sorted le4icographically, so all strings that start with EabcF will come be$ore all strings that start with Eabd F6

C.a+ter 78 6T= Algorit.ms


_________________________________________________________________________________________________________

Consider the followin& pro#lem= suppose that we want to write a pro&ram that reads in a list of inte&ers from a file Kperhaps representin& &rades on an assi&nmentL- then prints out the avera&e of those values! 8or simplicity- let's assume that this data is stored in a file called data.t+t with one inte&er per line! 8or e)ample= File: data.txt
100 -* -( -, , ,, 100 ...

/ere is one simple pro&ram that reads in the contents of the file- stores them in an ST computes the avera&e- then prints it out=
.in*lude iostream) .in*lude fstream) .in*lude set) using names$a*e std; int main() { ifstream in$ut(/data.t+t/); multiset int) values; "3 Iead the data from the file. 3" int *urrJalue; 'hile (in$ut )) *urrJalue) values.insert(*urrJalue); "3 5om$ute the average. 3" double total = 0.0; for (multiset int)44iterator itr = values.begin(); itr 1= values.end(); !!itr) total != 3itr; *out /Average is4 / total " values.siUe() endl;

multiset-

,s written- this code is perfectly le&al and will work as intended! /owever- there's somethin& sli&htly odd a#out it! 'f you were to descri#e what this pro&ram needs to do in plain Jn&lish- it would pro#a#ly #e somethin& like this= 1. Fead the contents of the file! 2. ,dd the values to&ether! 3. 2ivide #y the num#er of elements!

1 16A 1

Chapter <& ,TL Algorithms

'n some sense- the a#ove code matches this template! The first loop of the pro&ram reads in the contents of the file- the second loop sums to&ether the values- and the last line divides #y the num#er of elements! /owever- the code we've written is somewhat unsatisfactory! Consider this first loop=
int *urrJalue; 'hile (in$ut )) *urrJalue) values.insert(*urrJalue);

,lthou&h the intuition #ehind this loop is 4read the contents of the file into the multiset-6 the way the code is actually written is 4create an inte&er- and then while it's possi#le to read another element out of the file- do so and insert it into the multiset!6 This is a very mechanical means for insertin& the values into the multiset! Gur Jn&lish description of this process is 4read the file contents into the multiset-6 #ut the actual code is a step1#y1step process for e)tractin& data from the file one step at a time and insertin& it into the multiset! Similarly- consider this second loop- which sums to&ether the elements of the multiset=
double total = 0.0; for (multiset int)44iterator itr = values.begin(); itr 1= values.end(); !!itr) total != 3itr;

,&ain- we find ourselves takin& a very mechanical view of the operation! Gur Jn&lish description 4sum the elements to&ether6 is realized here as 4initialize the total to zero- then iterate over the elements of the multiset- increasin& the total #y the value of the current element at each step!6 The reason that we must issue commands to the computer in this mechanical fashion is precisely #ecause the computer is mechanical ( it's a machine for efficiently computin& functions! The challen&e of pro&rammin& is findin& a way to translate a hi&h1level set of commands into a series of low1level instructions that control the machine! This is often a chore- as the #asic operations e)ported #y the computer are fairly limited! 7ut pro&rammin& doesn't have to #e this difficult! ,s you've seen- we can define new functions in terms of old ones- and can #uild comple) pro&rams out of these increasin&ly more powerful su#routines! 'n theory- you could compile an enormous li#rary containin& solutions to all nontrivial pro&rammin& pro#lems! 0ith this li#rary in tow- you could easily write pro&rams #y *ust stitchin& to&ether these prewritten components! Unfortunately- there is no one li#rary with the solutions to every pro&rammin& pro#lem! /owever- this hasn't stopped the desi&ners of the ST from tryin& their #est to #uild one! These are the ST al&orithmsa li#rary of incredi#ly powerful routines for processin& data! The ST al&orithms can't do everythin&- #ut what they can do they do fantastically! 'n fact- usin& the ST al&orithms- it will #e possi#le to rewrite the pro&ram that avera&es num#ers in $our lines o$ code! This chapter details many common ST al&orithmsalon& with applications! Gnce you've finished this chapter- you'll have one of the most powerful standard li#raries of any pro&rammin& lan&ua&e at your disposal- and you'll #e ready to take on increasin&ly #i&&er and more impressive software pro*ects! Mour 2irst Algorit.m8 accumulate et's #e&in our tour of the ST al&orithms #y *umpin& in head1first! 'f you'll recall- the second loop from the avera&in& pro&ram looks like this=
double total = 0.0; for (multiset int)44iterator itr = values.begin(); itr 1= values.end(); !!itr) total != 3itr; *out /Average is4 / total " values.siUe() endl;

Chapter <& ,TL Algorithms This code is entirely e5uivalent to the followin&=
*out a**umulate(values.begin(), values.end(), 0.0) " values.siUe()

1 16? 1

endl;

0e've replaced the entire for loop with a sin&le call to a**umulate- eliminatin& a#out a third of the code from our ori&inal pro&ram! The a**umulate function- defined in the numeri*) header- takes three parameters ( two iterators that define a ran&e of elements- and an initial value to use in the summation! 't then computes the sum of all of the elements contained in the ran&e of iterators- plus the #ase value! P 0hat's #eautiful a#out a**umulate Kand the ST al&orithms in &eneralL is that a**umulate can take in iterators of any type! That is- we can sum up iterators from a multiset- a ve*tor- or de[ue! This means that if you ever find yourself needin& to compute the sum of the elements contained in a container- you can pass the begin() and end() iterators of that container into a**umulate to &et the sum! Boreover- a**umulate can accept any valid iterator ran&e- not *ust an iterator ran&e spannin& an entire container! 8or e)ample- if we want to compute the sum of the elements of the multiset that are #etween A; and 1@D- inclusive- we could write
a**umulate(values.lo'erLbound(GE), values.u$$erLbound(8CD), 0);

7ehind the scenes- a**umulate is implemented as a template function that accepts two iterators and simply uses a loop to sum to&ether the values! /ere's one possi#le implementation of a**umulate=
tem$late t%$ename (n$ut(terator, t%$ename ;%$e) inline ;%$e a**umulate((n$ut(terator start, (n$ut(terator sto$, ;%$e initial) { 'hile(start 1= sto$) { initial != 3start; !!start; # return initial; #

0hile some of the synta) specifics mi&ht #e a #it confusin& Knota#ly the template header and the inline keywordL- you can still see that the heart of the code is *ust a standard iterator loop that continuously advances the start iterator forward until it reaches the destination! There's nothin& ma&ic a#out a**umulate- and the fact that the function call is a sin&le line of code doesn't chan&e that it still uses a loop to sum all the values to&ether! 'f ST al&orithms are *ust functions that use loops #ehind the scenes- why even #other with them> There are several reasons- the first of which is simplicity! 0ith ST al&orithms- you can levera&e off of code that's already #een written for you rather than reinventin& the code from scratch! This can #e a &reat time1saver and also leads into the second reason- correctness! 'f you had to rewrite all the al&orithms from scratch every time you needed to use them- odds are that at some point you'd slip up and make a mistake! .ou mi&ht- for e)ample- write a sortin& routine that accidentally uses when you meant ) and conse5uently does not work at all! "ot so with the ST al&orithms ( they've #een thorou&hly tested and will work correctly for any &iven input! The third reason to use al&orithms is speed! 'n &eneral- you can assume that if there's an ST al&orithm that performs a task- it's &oin& to #e faster than most code you could write #y hand! Throu&h advanced techni5ues like template specialization and template metapro&rammin&- ST al&orithms are transparently optimized to work as fast as possi#le! 8inally- ST al&orithms offer clarity! 0ith al&orithms- you can immediately tell that a call to a**umulate adds up num#ers in a ran&e! 0ith a for loop that sums up values- you'd have to read each line in the loop #efore you understood what the code did!
P There is also a version of a**umulate that accepts four parameters- as you'll see in the chapter on functors!

1 166 1 Algorit.m @aming Con;entions

Chapter <& ,TL Algorithms

There are over fifty ST al&orithms Kdefined either in algorithm) or in numeri*)L- and memorizin& them all would #e a chore- to say the least! 8ortunately- many of them have common namin& conventions so you can reco&nize al&orithms even if you've never encountered them #efore! The suffi) Lif on an al&orithm Kre$la*eLif- *ountLif- etc!L means the al&orithm will perform a task on elements only if they meet a certain criterion! 8unctions endin& in Lif re5uire you to pass in a predicate function that accepts an element and returns a bool indicatin& whether the element matches the criterion! 8or e)ample consider the *ount al&orithm and its counterpart *ountLif! *ount accepts a ran&e of iterators and a value- then returns the num#er of times that the value appears in that ran&e! 'f we have a ve*tor int) of several inte&er values- we could print out the num#er of copies of the num#er 1@D in that ve*tor as follows=
*out *ount(m%Je*.begin(), m%Je*.end(), 8CD) endl;

*ountLif- on the other hand- accepts a ran&e of iterators and a predicate function- then returns the num#er of times the predicate evaluates to true in that ran&e! 'f we were interested in how num#er of even num#ers are contained in a ve*tor int)- we could could o#tain the value as follows! 8irst- we write a predicate function that takes in an int and returns whether it's even- as shown here= bool (sEven(int value) { return value \ E == 0; #

0e could then use *ountLif as follows=


*out *ountLif(m%Je*.begin(), m%Je*.end(), (sEven) endl;

,l&orithms containin& the word *o$% KremoveL*o$%- $artialLsortL*o$%- etc!L will perform some task on a ran&e of data and store the result in the location pointed at #y an e)tra iterator parameter! 0ith *o$% functions- you'll specify all the normal data for the al&orithm plus an e)tra iterator specifyin& a destination for the result! 0e'll cover what this means from a practical standpoint later! 'f an al&orithm ends in Ln KgenerateLn- sear*hLn, etcE- then it will perform a certain operation n times! These functions are useful for cases where the num#er of times you perform an operation is meanin&fulrather than the ran&e over which you perform it! To &ive you a #etter feel for what this means- consider the fill and fillLn al&orithms! Jach of these al&orithms sets a ran&e of elements to some specified value! 8or e)ample- we could use fill as follows to set every element in a de[ue to have value 0=
fill(m%9e[ue.begin(), m%9e[ue.end(), 0);

The fillLn al&orithm is similar to fill- e)cept that instead of acceptin& a ran&e of iterators- it takes in a start iterator and a num#er of elements to write! 8or instance- we could set the first ten elements of a de[ue to #e zero #y callin&
fillLn(m%9e[ue.begin(), 80, 0);

Iterator Categories 'f you'll recall from the discussion of the ve*tor and de[ue insert functions- to specify an iterator to the nth element of a ve*tor- we used the synta) m%Je*tor.begin() ! n! ,lthou&h this synta) is le&al in con*unction with ve*tor and de[ue- it is ille&al to use ! operator with iterators for other container classes

Chapter <& ,TL Algorithms

1 16D 1

like ma$ and set! ,t first this may seem stran&e ( after all- there's nothin& intuitively wron& with movin& a set iterator forward multiple steps- #ut when you consider how the set is internally structured the reasons #ecome more o#vious! Unlike ve*tor and de[ue- the elements in a ma$ or set are not stored se5uentially Kusually they're kept in a #alanced #inary treeL! Conse5uently- to advance an iterator n steps forward- the ma$ or set iterator must take n individual steps forward! Contrast this with a ve*tor iterator- where advancin& forward n steps is a simple addition Ksince all of the ve*tor's elements are stored conti&uouslyL! Since the runtime comple)ity of advancin& a ma$ or set iterator forward n steps is linear in the size of the *ump- whereas advancin& a ve*tor iterator is a constant1time operation- the ST disallows the ! operator for ma$ and set iterators to prevent su#tle sources of inefficiency! 7ecause not all ST iterators can efficiently or le&ally perform all of the functions of every other iteratorST iterators are cate&orized #ased on their relative power! ,t the hi&h end are random"access iterators that can perform all of the possi#le iterator functions- and at the #ottom are the input and output iterators which &uarantee only a minimum of functionality! There are five different types of iterators- each of which is discussed in short detail #elow! $ut+ut Iterators! Gutput iterators are one of the two weakest types of iterators! 0ith an output iterator- you can write values usin& the synta) 3m%(tr = value and can advance the iterator forward one step usin& the !! operator! /owever- you cannot read a value from an output iterator usin& the synta) value = 3m%(tr- nor can you use the != or Q operators! In+ut Iterators! 'nput iterators are similar to output iterators e)cept that they read values instead of writin& them! That is- you can write code alon& the lines of value = 3m%(tr- #ut not 3m%(tr = value! Boreover- input iterators cannot iterate over the same ran&e twice! 2orward Iterators! 8orward iterators com#ine the functionality of input and output iterators so that most intuitive operations are well1defined! 0ith a forward iterator- you can write #oth 3m%(tr = value and value = 3m%(tr! 8orward iterators- as their name su&&ests- can only move forward! Thus !!m%(tr is le&al- #ut --m%(tr is not! Bidirectional Iterators! 7idirectional iterators are the iterators e)posed #y ma$ and set and encompass all of the functionality of forward iterators! ,dditionally- they can move #ackwards with the decrement operator! Thus it's possi#le to write --m%(tr to &o #ack to the last element you visited- or even to traverse a list in reverse order! /owever- #idirectional iterators cannot respond to the ! or != operators! 4andom&Access Iterators! 2on't &et tripped up #y the name ( random1access iterators don't move around randomly! Fandom1access iterators &et their name from their a#ility to move forward and #ackward #y ar#itrary amounts at any point! These are the iterators employed #y ve*tor and de[ue and represent the ma)imum possi#le functionality- includin& iterator1from1 iterator su#traction- #racket synta)- and incrementation with ! and !=!

'f you'll notice- each class of iterators is pro&ressively more powerful than the previous one ( that is- the iterators form a functionality hierarchy! This means that when a li#rary function re5uires a certain class of iterator- you can provide it any iterator that's at least as powerful! 8or e)ample- if a function re5uires a forward iterator- you can provide either a forward- #idirectional- or random1access iterator! The iterator hierarchy is illustrated #elow=

1 16E 1
Random)A**+&& It+rator& itr != distan*e; itr ! distan*e; itr8 itrE; itr[m%(nde+]; ,idir+*tiona- It+rator& --itr; For.ard It+rator& In/0t It+rator& val = 3itr; !!itr; O0t/0t It+rator& 3itr = val; !!itr;

Chapter <& ,TL Algorithms

0hy cate&orize iterators this way> 0hy not make them all e5ually powerful> There are several reasons! 8irst- in some cases- certain iterator operations cannot #e performed efficiently! 8or instance- the ST ma$ and set are layered on top of #alanced #inary trees- a structure in which it is simple to move from one element to the ne)t #ut si&nificantly more comple) to *ump from one position to another ar#itrarily! 7y disallowin& the ! operator on ma$ and set iterators- the ST desi&ners prevent su#tle sources of inefficiency where simple code like itr ! H is unreasona#ly inefficient! Second- iterator cate&orization allows for #etter classification of the ST al&orithms! 8or e)ample- suppose that an al&orithm takes as input a pair of input iterators! 8rom this- we can tell that the al&orithm will not modify the elements #ein& iterated over- and so can feel free to pass in iterators to data that must not #e modified under any circumstance! Similarly- if an al&orithm has a parameter that is la#eled as an output iterator- it should #e clear from conte)t that the iterator parameter defines where data &enerated #y the al&orithm should #e written! 4eordering Algorit.ms There are a lar&e assortment of ST al&orithms at your disposal- so for this chapter it's useful to discuss the different al&orithms in terms of their #asic functionality! The first ma*or &roupin& of al&orithms we'll talk a#out are the reordering algorithms- al&orithms that reorder #ut preserve the elements in a container! Cerhaps the most useful of the reorderin& al&orithms is sort- which sorts elements in a ran&e in ascendin& order! 8or e)ample- the followin& code will sort a ve*tor int) from lowest to hi&hest=
sort(m%Je*tor.begin(), m%Je*tor.end()); sort re5uires that the iterators you pass in #e random1access iterators- so you cannot use sort to sort a ma$ or set! /owever- since ma$ and set are always stored in sorted order- this shouldn't #e a pro#lem!

7y default- sort uses the operator for whatever element types it's sortin&- #ut you can specify a different comparison function if you wish! 0henever you write a comparison function for an ST al&orithm- it should accept two parameters representin& the elements to compare and return a bool indicatin& whether the first element is strictly less than the second element! 'n other words- your call#ack should mimic the operator! 8or e)ample- suppose we had a ve*tor $la*e;)- where $la*e; was defined as
stru*t $la*e; { int +; int %; #;

Chapter <& ,TL Algorithms Then we could sort the ve*tor only if we wrote a comparison function for $la*e;s!P 8or e)ample=
bool 5om$are<la*es($la*e; one, $la*e; t'o) { if(one.+ 1= t'o.+) return one.+ t'o.+; return one.% t'o.%; # sort(m%<la*eJe*tor.begin(), m%<la*eJe*tor.end(), 5om$are<la*es);

1 16< 1

.ou can also use custom comparison functions even if a default already e)ists! 8or e)ample- here is some code that sorts a ve*tor string) #y len&th- i&norin& whether the strin&s are in alpha#etical order=
bool 5om$are6tring7ength(string one, string t'o) { return one.length() t'o.length(); # sort(m%Je*tor.begin(), m%Je*tor.end(), 5om$are6tring7ength);

Gne last note on comparison functions is that they should either accept the parameters #y value or #y 4reference to *onst!6 Since we haven't covered *onst yet- for now your comparison functions should accept their parameters #y value! Gtherwise you can &et some pretty ferocious compiler errors! ,nother useful reorderin& function is randomLshuffle- which randomly scram#les the elements of a container! 7ecause the scram#lin& is random- there's no need to pass in a comparison function! /ere's some code that uses randomLshuffle to scram#le a ve*tor's elements=
randomLshuffle(m%Je*tor.begin(), m%Je*tor.end());

,s with sort- the iterators must #e random1access iterators- so you can't scram#le a set or ma$! Then a&ain- since they're sorted containers- you shouldn't want to do this in the first place! 'nternally- randomLshuffle uses the #uilt1in rand() function to &enerate random num#ers! ,ccordin&lyyou should use the srand function to seed the randomizer #efore usin& randomLshuffle! The last ma*or al&orithm in this cate&ory is rotate- which cycles the elements in a container! 8or e)ample- &iven the input container K0- 1- ;- @- A- ?L- rotatin& the container around position @ would result in the container K;- @- A- ?- 0- 1L! The synta) for rotate is anomalous in that it accepts three iterators delineatin& the ran&e and the new front- #ut in the order begin- middle- end! 8or e)ample- to rotate a ve*tor around its third position- we would write
rotate(v.begin(), v.begin() ! E, v.end());

6earc.ing Algorit.ms Commonly you're interested in checkin& mem#ership in a container! 8or e)ample- &iven a ve*tor- you mi&ht want to know whether or not it contains a specific element! 0hile the ma$ and set naturally support find- ve*tors and de[ues lack this functionality! 8ortunately- you can use ST al&orithms to correct this pro#lem!

P 0hen we cover operator overloadin& in the second half of this te)t- you'll see how to create functions that will use automatically!

sort

1 1D0 1

Chapter <& ,TL Algorithms

To search for an element in a container- you can use the find function! find accepts two iterators delineatin& a ran&e and a value- then returns an iterator to the first element in the ran&e with that value! 'f nothin& in the ran&e matches- find returns the second iterator as a sentinel! 8or e)ample=
if(find(m%Je*tor.begin(), m%Je*tor.end(), 8CD) 1= m%Je*tor.end()) "3 ... ve*tor *ontains 8CD ... 3"

,lthou&h you can le&ally pass ma$ and set iterators as parameters to find- you should avoid doin& so! 'f a container class has a mem#er function with the same name as an ST al&orithm- you should use the mem#er function instead of the al&orithm #ecause mem#er functions can use information a#out the container's internal data representation to work much more 5uickly! ,l&orithms- however- must work for all iterators and thus can't make any optimizations! ,s an e)ample- with a set containin& one million elements- the set's find mem#er function can locate elements in around twenty steps usin& #inary search- while the ST find function could take up to one million steps to linearly iterate over the entire container! That's a sta&&erin& difference and really should hit home how important it is to use mem#er functions over ST al&orithms! $ust as a sorted ma$ and set can use #inary search to outperform the linear ST find al&orithm- if you have a sorted linear container Kfor e)ample- a sorted ve*torL- you can use the ST al&orithm binar%Lsear*h to perform the search in a fraction of the time! 8or e)ample=
"3 Assume m%Je*tor is sorted. 3" if (binar%Lsear*h(m%Je*tor.begin(), m%Je*tor.end(), 8CD)) { "3 ... &ound 8CD ... 3" #

,lso- as with sort- if the container is sorted usin& a special comparison function- you can pass that function in as a parameter to binar%Lsear*h! /owever- make sure you're consistent a#out what comparison function you use- #ecause if you mi) them up binar%Lsear*h mi&ht not work correctly! "ote that binar%Lsear*h doesn't return an iterator to the element ( it simply checks to see if it's in the container! 'f you want to do a #inary search in order to &et an iterator to an element- you can use the lo'erLbound al&orithm which- like the ma$ and set lo'erLbound functions- returns an iterator to the first element &reater than or e5ual to the specified value! "ote that lo'erLbound mi&ht hand #ack an iterator to a different element than the one you searched for if the element isn't in the ran&e- so #e sure to check the return value #efore usin& it! ,s with binar%Lsear*h- the container must #e in sorted order for lo'erLbound al&orithm to work correctly! Iterator Ada+tors The al&orithms that we've encountered so far do not produce any new data ran&es! The sort al&orithm rearran&es data without &eneratin& new values! binar%Lsear*h and a**umulate scan over data ran&es#ut yield only a sin&le value! /owever- there are a &reat many ST al&orithms that take in ran&es of data and produce new data ran&es at output! ,s a simple e)ample- consider the *o$% al&orithm! ,t a hi&h level- *o$% takes in a ran&e of data- then duplicates the values in that ran&e at another location! Concretely- *o$% takes in three parameters ( two input iterators definin& a ran&e of values to copy- and an output iterator indicatin& where the data should #e written! 8or e)ample- &iven the followin& setup=

Chapter <& ,TL Algorithms


start ^ 0 result ^ 0 0 0 0 0 0 0 1 ( 3 ) *

1 1D1 1
sto$ ^ +

,fter callin& *o$%(start, sto$, result)- the result is as follows=


start ^ 0 result ^ 0 1 ( 3 ) * + 1 ( 3 ) * sto$ ^ +

0hen usin& al&orithms like *o$% that &enerate a ran&e of data- you must make sure that the destination has enou&h space to hold the result! ,l&orithms that &enerate data ran&es work #y overwriting elements in the ran&e #e&innin& with the specified iterator- and if your output iterator points to a ran&e that doesn't have enou&h space the al&orithms will write off past the end of the ran&e- resultin& in undefined #ehavior! 7ut here we reach a wonderful parado)! 0hen runnin& an al&orithm that &enerates a ran&e of data- you must make sure that sufficient space e)ists to hold the result! /owever- in some cases you can't tell how much data is &oin& to #e &enerated until you actually run the al&orithm! That is- the only way to determine how much space you'll need is to run the al&orithm- which mi&ht result in undefined #ehavior #ecause you didn't allocate enou&h space! To #reak this cycle- we'll need a special set of tools called iterator adaptors! 'terator adaptors Kdefined in the iterator) headerL are o#*ects that act like iterators ( they can #e dereferenced with 3 and advanced forward with !! ( #ut which don't actually point to elements of a container! To &ive a concrete e)amplelet's consider the ostreamLiterator! ostreamLiterators are o#*ects that look like output iterators! That is- you can dereference them usin& the 3 operator- advance them forward with the !! operator- etc! /owever- ostreamLiterators don't actually point to elements in a container! 0henever you dereference an ostreamLiterator and assi&n a value to it- that value is printed to a specified output stream- such as *out or an ofstream! /ere's some code showin& off an ostreamLiteratorQ the para&raph after it e)plores how it works in a #it more detail=
"3 9e*lare an ostreamLiterator that 'rites ints to *out. 3" ostreamLiterator int) m%(tr(*out, / /); "3 2rite values to the iterator. ;hese values 'ill be $rinted to *out. 3" 3m%(tr = 8CD; "" <rints 8CD to *out !!m%(tr; 3m%(tr = GE; !!m%(tr "" <rints GE to *out

'f you compile and run this code- you will notice that the num#ers 1@D and A; &et written to the consoleseparated #y spaces! ,lthou&h it loo*s like you're manipulatin& the contents of a container- you're actually writin& characters to the *out stream!

1 1D; 1

Chapter <& ,TL Algorithms

et's consider this code in a #it more detail! 'f you'll notice- we declared the ostreamLiterator #y writin&
ostreamLiterator int) m%(tr(*out, / /);

There are three important pieces of data in this line of code! 8irst- notice that ostream[iterator is a parameterized type- much like the ve*tor or set! 'n the case of ostreamLiterator- the template ar&ument indicates what sorts of value will #e written to this iterator! That is- an ostreamLiterator int) writes ints into a stream- while an ostreamLiterator string) would write strin&s! Second- notice that when we created the ostreamLiterator- we passed it two pieces of information! 8irst- we &ave the ostreamLiterator a stream to write to- in this case *out! Second- we &ave it a separator string- in our case a strin& holdin& a sin&le space! 0henever a value is written to an ostreamLiterator- that value is pushed into the specified stream- followed #y the separator strin&! ,t this point- iterator adaptors mi&ht seem like little more than a curiosity! Sure- we can use an ostreamLiterator to write values to *out- #ut we could already do that directly with *out! So what makes the iterator adaptors so useful> The key point is that iterator adaptors are iterators- and so they can #e used in con*unction with the ST al&orithms! 0henever an ST al&orithm e)pects a re&ular iteratoryou can supply an iterator adaptor instead to 4trick6 the al&orithm into performin& some comple) task when it #elieves it's *ust writin& values to a ran&e! 8or e)ample- let's revisit the *o$% al&orithm now that we have ostreamLiterators! 0hat happens if we use *o$% to copy values from a container to an ostreamLiterator> That is- what is the output of the followin& code=
*o$%(m%Je*tor.begin(), m%Je*tor.end(), ostreamLiterator int)(*out, / /));

This code copies all of the elements from the m%Je*tor container to the ran&e specified #y the ostreamLiterator! "ormally- *o$% would duplicate the values from m%Je*tor at another location- #ut since we've written the values to an ostreamLiterator- this code will instead print all of the values from the ve*tor to *out- separated #y spaces! This means that this sin&le line of code prints out m%Je*torR Gf course- this is *ust one of many iterator adaptors! 0e initially discussed iterator adaptors as a way to #reak the 4vicious cycle6 where al&orithms need space to hold their results- #ut the amount of space needed can only #e calculated #y runnin& the al&orithm! To resolve this issue- the standard li#rary provides a collection of special iterator adapters called insert iterators! These are output iterators thatwhen written to- insert the value into a container usin& one of the insert- $ushLba*B- or $ushLfront functions! ,s a simple e)ample- let's consider the ba*BLinsertLiterator! ba*BLinsertLiterator is an iterator that- when written to- calls $ushLba*B on a specified ST se5uence containers Ki!e! ve*tor or de[ueL to store the value! 8or e)ample- consider the followin& code snippet=
ve*tor int) m%Je*tor; "3 (nitiall% em$t% 3" "3 5reate a ba*BLinsertLiterator that inserts values into m%Je*tor. 3" ba*BLinsertLiterator ve*tor int) ) itr(m%Je*tor); for (int i = 0; i 80; !!i) { 3itr = i; "" /2rite/ to the ba*BLinsertLiterator, a$$ending the value. !!itr; # "3 <rint the ve*tor *ontents; this dis$la%s 0 1 ( 3 ) * + , - 3" *o$%(m%Je*tor.begin(), m%Je*tor.end(), ostreamLiterator int)(*out, / /));

This code is fairly dense- so let's &o over it in some more detail! The first line simply creates an empty ve*tor int). The ne)t line is

Chapter <& ,TL Algorithms


ba*BLinsertLiterator ve*tor int) ) itr(m%Je*tor);

1 1D@ 1

This code creates a ba*BLinsertLiterator which inserts into a ve*tor int)! This synta) mi&ht #e a #it stran&e- since the iterator type is parameterized over the type of the container it inserts into- not the type of the elements stored in that container! Boreover- notice that we indicated to the iterator that it should insert into the m%Je*tor container #y surroundin& the container name in parentheses! 8rom this point- any values written to the ba*BLinsertLiterator will #e stored inside of m%Je*tor #y callin& $ushLba*B! 0e then have the followin& loop- which indirectly adds elements to the ve*tor=
for (int i = 0; i 80; !!i) { 3itr = i; "" /2rite/ to the ba*BLinsertLiterator, a$$ending the value. !!itr; #

/ere- the line 3itr = i will implicitly call m%Je*tor.$ushLba*B(i)- addin& the value to the ve*tor! Thus- when we encounter the final line=
*o$%(m%Je*tor.begin(), m%Je*tor.end(), ostreamLiterator int)(*out, / /));

the call to *o$% will print out the num#ers 0 throu&h <- inclusive- since they've #een stored in the ve*tor! 'n practice- it is rare to see ba*BLinsertLiterator used like this! This type of iterator is almost e)clusively used as a parameter to ST al&orithms that need a place to store a result! 8or e)ampleconsider the reverseL*o$% al&orithm! ike *o$%- reverseL*o$% takes in three iterators- two delineatin& an input ran&e and one specifyin& a destination- then copies the elements from the input ran&e to the destination! /owever- unlike the re&ular *o$% al&orithm- reverseL*o$% copies the elements in reverse order! 8or e)ample- usin& reverseL*o$% to copy the se5uence 0- 1- ;- @- A to a destination would cause the destination ran&e to hold the se5uence A- @- ;- 1- 0! Suppose that we are interested in usin& the reverseL*o$% al&orithm to make a copy of a ve*tor with the elements in reverse order as the ori&inal! Then we could do so as follows=
ve*tor int) original = "3 ... 3" ve*tor int) destination; reverseL*o$%(original.begin(), original.end(), ba*BLinsertLiterator ve*tor int) )(destination));

The synta) ba*BLinsertLiterator ve*tor int) ) is admittedly #it clunky- and fortunately there's a shorthand! To create a ba*BLinsertLiterator that inserts elements into a particular container- you can write
ba*BLinserter(*ontainer);

Thus the a#ove code with reverse_*o$% could #e rewritten as


ve*tor int) original = "3 ... 3" ve*tor int) destination; reverseL*o$%(original.begin(), original.end(), ba*BLinserter(destination));

This is much cleaner than the ori&inal and is likely to #e what you'll see in practice! The ba*BLinserter is a particularly useful container when you wish to store the result of an operation in a ve*tor or de[ue- #ut cannot #e used in con*unction with ma$ or set #ecause those containers do not

1 1DA 1

Chapter <& ,TL Algorithms

support the $ushLba*B mem#er function! 8or those containers- you can use the more &eneral insertLiterator- which insert elements into ar#itrary positions in a container! , &reat e)ample of insertLiterator in action arises when computin& the union- intersection- or difference of two sets! Bathematically speakin&- the union of two sets is the set of elements contained in either of the sets- the intersection of two sets is the set of elements contained in both of the sets- and the di$$erence of two sets is the set of elements contained in the first set #ut not in the second! These operations are e)ported #y the ST al&orithms as setLunion- setLinterse*tion- and setLdifferen*e! These al&orithms take in five parameters ( two pairs of iterator ran&es definin& what ran&es to use as the input sets- alon& with one final iterator indicatin& where the result should #e written! ,s with all ST al&orithms- the set al&orithms assume that the destination ran&e has enou&h space to store the result of the operation- and a&ain we run into a pro#lem #ecause we cannot tell how many elements will #e produced #y the al&orithm! This is an ideal spot for an insertLiterator! 3iven two sets one and t'o- we can compute the union of those two sets as follows=
set int) result; setLunion(set=ne.begin(), set=ne.end(), "" All of the elements in set=ne set;'o.begin(), set;'o.end(), "" All of the elements in set;'o inserter(result, result.begin())); "" 6tore in result.

"otice that the last parameter is inserter(result, result.begin())! This is an insert iterator that inserts its elements into the result set! 8or somewhat technical reasons- when insertin& elements into a set- you must specify #oth the container and the container's begin iterator as parameters- thou&h the &enerated elements will #e stored in sorted order! ,ll of the iterator adaptors we've encountered so far have #een used to channel the output of an al&orithm to a location other than an e)istin& ran&e of elements! ostreamLiterator writes values to streamsba*BLinsertLiterator invokes $ushLba*B to make space for its elements- etc! /owever- there is a particularly useful iterator adapter- the istreamLiterator- which is an input iterator! That isistreamLiterators can #e used to provide data as inputs to particular ST al&orithms! ,s its name su&&ests- istreamLiterator can #e used to read values from a stream as if it were a container of elements! To illustrate istreamLiterator- let's return to the e)ample from the start of this chapter! 'f you'll recall- we wrote a pro&ram that read in a list of num#ers from a file- then computed their avera&e! 'n this pro&ram- we read in the list of num#ers usin& the followin& 'hile loop=
int *urrJalue; 'hile (in$ut )) *urrJalue) values.insert(*urrJalue);

/ere- values is a multiset int)! This code is e5uivalent to the followin&- which uses the ST *o$% al&orithm in con*unction with an inserter and two istreamLiterators=
*o$%(istreamLiterator int)(in$ut), istreamLiterator int)(), inserter(values, values.begin());

This is perhaps the densest sin&le line of code we've encountered yet- so let's dissect it to see how it works! Fecall that the *o$% al&orithm copies the values from an iterator ran&e and stores them in the ran&e specified #y the destination iterator! /ere- our destination is an inserter that adds elements into the values multiset! Gur input is the pair of iterators
istreamLiterator int)(in$ut), istreamLiterator int)()

0hat e)actly does this mean> 0henever a value is read from an istreamLiterator- the iterator uses the stream e)traction operator )) to read a value of the proper type from the input stream- then returns it!

Chapter <& ,TL Algorithms

1 1D? 1

Conse5uently- the iterator istreamLiterator int)(in$ut) is an iterator that reads int values out of the stream in$ut! The second iterator- istreamLiterator int)()- is a #it stran&er! This is a special istreamLiterator called the end"o$"stream iterator! 0hen definin& ran&es with ST iterators- it is always necessary to specify two iterators- one for the #e&innin& of the ran&e and one that is one past the end of it! 0hen workin& with ST containers this is perfectly fine- since the size of the container is known! /owever- when workin& with streams- it's unclear e)actly how many elements that stream will contain! 'f the stream is an ifstream- the num#er of elements that can #e read depends on the contents of the file! 'f the stream is *in- the num#er of elements that can #e read depends on how many values the user decides to enter! To &et around this- the ST desi&ners used a #it of a hack! 0hen readin& values from a stream with an istreamLiterator- whenever no more data is availa#le in the stream Keither #ecause the stream entered a fail state- or #ecause the end of the file was reachedL- the istreamLiterator takes on a special value which indicates 4there is no more data in the stream!6 This value can #e formed #y constructin& an istreamLiterator without specifyin& what stream to read from! Thus in the code
*o$%(istreamLiterator int)(in$ut), istreamLiterator int)(), inserter(values, values.begin());

the two istreamLiterators define the ran&e from the #e&innin& of the input stream up until no more values can #e read from the stream! The followin& ta#le lists some of the more common iterator adapters and provides some useful conte)t! .ou'll likely refer to this ta#le most when writin& code that uses al&orithms!
ba*BLinsertLiterator 5ontainer) ba*BLinsertLiterator ve*tor int) ) itr(m%Je*tor); ba*BLinsertLiterator de[ue *har) ) itr = ba*BLinserter(m%9e[ue);

,n output iterator that stores elements #y callin& $ushLba*B on the specified container! .ou can declare ba*BLinsertLiterators e)plicitlyor can create them with the function ba*BLinserter!
frontLinsertLiterator 5ontainer) frontLinsertLiterator de[ue int) ) itr(m%(nt9e[ue); frontLinsertLiterator de[ue *har) ) itr = frontLinserter(m%9e[ue);

,n output iterator that stores elements #y callin& $ushLfront on the specified container! Since the container must have a $ushLfront mem#er function- you cannot use a frontLinsertLiterator with a ve*tor! ,s with ba*BLinsertLiterator- you can create frontLinsertLiterators with the the frontLinserter function!
insertLiterator 5ontainer) insertLiterator set int) ) itr(m%6et, m%6et.begin()); insertLiterator set int) ) itr = inserter(m%6et, m%6et.begin());

,n output iterator that stores its elements #y callin& insert on the specified container to insert elements at the indicated position! .ou can use this iterator type to insert into any container- especially set! The special function inserter &enerates insertLiterators for you!

1 1D6 1
ostreamLiterator ;%$e)

Chapter <& ,TL Algorithms


ostreamLiterator int) itr(*out, / /); ostreamLiterator *har) itr(*out); ostreamLiterator double) itr(m%6tream, /,n/);

,n output iterator that writes elements into an output stream! 'n the constructor- you must initialize the ostreamLiterator to point to an ostream- and can optionally provide a separator strin& written after every element!
istreamLiterator ;%$e) istreamLiterator int) itr(*in); istreamLiterator int) end(tr; "" Ieads from *in "" 6$e*ial end value

,n input iterator that reads values from the specified istream when dereferenced! 0hen istreamLiterators reach the end of their streams Kfor e)ample- when readin& from a fileL- they take on a special 4end6 value that you can &et #y creatin& an istreamLiterator with no parameters! istreamLiterators are suscepti#le to stream failures and should #e used with care!
ostreambufLiterator *har) ostreambufLiterator *har) itr(*out); "" 2rite to *out

+n o#tp#t iterator that writes raw character data to an o#tp#t stream. @nli0e ostreamLiterator, which can print val#es o* any type, ostreambufLiterator can only write individ#al characters. ostreambufLiterator is #s#ally #sed in conA#nction with istreambufLiterator.
istreambufLiterator *har) istreambufLiterator *har) itr(*in); "" Iead data from *in istreambufLiterator *har) end(tr; "" 6$e*ial end value

+n inp#t iterator that reads #n*ormatted data *rom an inp#t stream. istreambufLiterator always reads in character data and will not s0ip over whitespace. Bi0e istreamLiterator, istreambufLiterators have a special iterator constr#cted with no parameters which indicates Cend o* stream.D istreambufLiterator is #sed primarily to read raw data *rom a *ile *or processin/ with the %TB al/orithms.

4emo;al Algorit.ms The ST provides several al&orithms for removin& elements from containers! al&orithms have some idiosyncrasies that can take some time to ad*ust to! /owever- removal

2espite their name- removal al&orithms do not actually remove elements from containers! This is somewhat counterintuitive #ut makes sense when you think a#out how al&orithms work! ,l&orithms accept iterators- not containers- and thus do not know how to erase elements from containers! Femoval functions work #y shufflin& down the contents of the container to overwrite all elements that need to #e erased! Gnce finished- they return iterators to the first element not in the modified ran&e! So for e)ampleif you have a ve*tor initialized to 0- 1- ;- @- @- @- A and then remove all instances of the num#er @- the resultin& ve*tor will contain 0- 1- ;- A- @- @- A and the function will return an iterator to one spot past the first A! 'f you'll notice- the elements in the iterator ran&e startin& at begin and endin& with the element one past the four are the se5uence 0- 1- ;- A ( e)actly the ran&e we wanted! To truly remove elements from a container with the removal al&orithms- you can use the container class mem#er function erase to erase the ran&e of values that aren't in the result! 8or e)ample- here's a code snippet that removes all copies of the num#er 1@D from a ve*tor=
m%Je*tor.erase(remove(m%Je*tor.begin(), m%Je*tor.end(), 8CD), m%Je*tor.end());

Chapter <& ,TL Algorithms

1 1DD 1

"ote that we're erasin& elements in the ran&e N 3- endL- where 3 is the value returned #y the remove al&orithm! There is another useful removal function- removeLif- that removes all elements from a container that satisfy a condition specified as the final parameter! 8or e)ample- usin& the is$un*t function from the header file **t%$e)- we can write a 6tri$<un*tuation function that returns a copy of a strin& with all the punctuation removed=P
string 6tri$<un*tuation(string in$ut) { in$ut.erase(removeLif(in$ut.begin(), in$ut.end(), is$un*t), in$ut.end()); return in$ut; #

K'sn't it amazin& how much you can do with a sin&le line of code> That's the real #eauty of ST al&orithms!L 'f you're shaky a#out how to actually remove elements in a container usin& remove- you mi&ht want to consider the removeL*o$% and removeL*o$%Lif al&orithms! These al&orithms act *ust like remove and removeLif- e)cept that instead of modifyin& the ori&inal ran&e of elements- they copy the elements that aren't removed into another container! 0hile this can #e a #it less memory efficient- in some cases it's e)actly what you're lookin& for! $t.er @otewort./ Algorit.ms The past few sections have focused on common &enera of al&orithms- pickin& out representatives that illustrate the #ehavior of particular al&orithm classes! /owever- there are many noteworthy al&orithms that we have not discussed yet! This section covers several of these al&orithms- includin& useful e)amples! , surprisin&ly useful al&orithm is transform- which applies a function to a ran&e of elements and stores the result in the specified destination! transform accepts four parameters ( two iterators delineatin& an input ran&e- an output iterator specifyin& a destination- and a call#ack function- then stores in the output destination the result of applyin& the function to each element in the input ran&e! ,s with other al&orithms- transform assumes that there is sufficient stora&e space in the ran&e pointed at #y the destination iterator- so make sure that you have sufficient space #efore transformin& a ran&e!
transform is particularly ele&ant when com#ined with functors- #ut even without them is useful for a whole ran&e of tasks! 8or e)ample- consider the tolo'er function- a C li#rary function declared in the header **t%$e) that accepts a *har and returns the lowercase representation of that character! Com#ined with transform- this lets us write 5onvert;o7o'er5ase from strutils.h in two lines of code- one of which is a return statement= string 5onvert;o7o'er5ase(string te+t) { transform(te+t.begin(), te+t.end(), te+t.begin(), tolo'er); return te+t; #

"ote that after specifyin& the ran&e te+t.begin()- te+t.end() we have another call to te+t.begin()! This is #ecause we need to provide an iterator that tells transform where to put its output! Since we want to overwrite the old contents of our container with the new values- we specify te+t.begin() another time to indicate that transform should start writin& elements to the #e&innin& of the strin& as it &enerates them!
P Gn some compilers- this code will not compile as written! See the later section on compati#ility issues for more information!

1 1DE 1

Chapter <& ,TL Algorithms

There is no re5uirement that the function you pass to transform return elements of the same type as those stored in the container! 't's le&al to transform a set of strings into a set of doubles- for e)ample! Bost of the al&orithms we've seen so far operate on entire ran&es of data- #ut not all al&orithms have this property! Gne of the most useful Kand innocuous1seemin&L al&orithms is s'a$- which e)chan&es the values of two varia#les! 0e first encountered s'a$ two chapters a&o when discussin& sortin& al&orithms#ut it's worth repeatin&! Several advanced C++ techni5ues hin&e on s'a$'s e)istence- and you will almost certainly encounter it in your day1to1day pro&rammin& even if you eschew the rest of the ST ! Two last al&orithms worthy of mention are the minLelement and ma+Lelement al&orithms! These al&orithms accept as input a ran&e of iterators and return an iterator to the lar&est element in the ran&e! ,s with other al&orithms- #y default the elements are compared #y - #ut you can provide a #inary comparison function to the al&orithms as a final parameter to chan&e the default comparison order! The followin& ta#le lists some of the more common ST al&orithms! 't's #y no means an e)haustive listand you should consult a reference to &et a complete list of all the al&orithms availa#le to you!
;%$e a**umulate((n$ut(tr start, (n$ut(tr sto$, ;%$e value)

Feturns the sum of the elements in the ran&e N start- sto$L plus the value of value!

bool binar%Lsear*h(Iandom(tr start, Cerforms #inary search on the sorted ran&e specified #y Iandom(tr sto$, Nstart- sto$L and returns whether it finds the element value! 'f *onst ;%$e? value)

the elements are sorted usin& a special comparison function- you must specify the function as the final parameter!

=ut(tr *o$%((n$ut(tr start, (n$ut(tr sto$, =ut(tr out$ut6tart) siUeLt *ount((n$ut(tr start, (n$ut(tr end, *onst ;%$e? value)

Copies the elements in the ran&e N start- sto$L into the output ran&e startin& at out$ut6tart! *o$% returns an iterator to one past the end of the ran&e written to! Feturns the num#er of elements in the ran&e N start- sto$L e5ual to value!

siUeLt *ountLif((n$ut(tr start, Feturns the num#er of elements in the ran&e N start- sto$L for (n$ut(tr end, which fn returns true! Useful for determinin& how many elements <redi*ate&un*tion fn)

have a certain property!

bool e[ual((n$ut(tr start8, (n$ut(tr sto$8, (n$ut(tr startE)

Feturns whether elements contained in the ran&e defined #y Nstart8- sto$8L and the ran&e #e&innin& with start; are e[ual! 'f you have a special comparison function to compare two elementsyou can specify it as the final parameter! Feturns two iterators as a $air that defines the su#1ran&e of elements in the sorted ran&e N start- sto$L that are e5ual to value! 'n other words- every element in the ran&e defined #y the returned iterators is e5ual to value! .ou can specify a special comparison function as a final parameter! Sets every element in the ran&e Nstart- sto$L to value! Sets the first num elements- startin& at start- to value! Feturns an iterator to the first element in N start- sto$L that is e5ual to value- or sto$ if the value isn't found! The ran&e doesn't need to #e sorted!

$air Iandom(tr, Iandom(tr) e[ualLrange(Iandom(tr start, Iandom(tr sto$, *onst ;%$e? value)

void fill(&or'ard(tr start, &or'ard(tr sto$, *onst ;%$e? value) void fillLn(&or'ard(tr start, siUeLt num, *onst ;%$e? value) (n$ut(tr find((n$ut(tr start, (n$ut(tr sto$, *onst ;%$e? value)

Chapter <& ,TL Algorithms


(n$ut(tr findLif((n$ut(tr start, (n$ut(tr sto$, <redi*ate&un* fn) &un*tion forLea*h((n$ut(tr start, (n$ut(tr sto$, &un*tion fn) void generate(&or'ard(tr start, &or'ard(tr sto$, Generator fn); void generateLn(=ut$ut(tr start, siUeLt n, Generator fn); bool in*ludes((n$ut(tr (n$ut(tr (n$ut(tr (n$ut(tr start8, sto$8, startE, sto$E)

1 1D< 1
Feturns an iterator to the first element in N start- sto$L for which fn is true- or sto$ otherwise! Calls the function fn on each element in the ran&e Nstart- sto$L! Calls the zero1parameter function fn once for each element in the ran&e Nstart- sto$L- storin& the return values in the ran&e! Calls the zero1parameter function fn n times- storin& the results in the ran&e #e&innin& with start! Feturns whether every element in the sorted ran&e NstartE- sto$EL is also in N start8- sto$8L! 'f you need to use a special comparison function- you can specify it as the final parameter!

;%$e innerL$rodu*t((n$ut(tr start8, Computes the inner product of the values in the ran&e Nstart1(n$ut(tr sto$8, stop1L and Nstart;- start; + Kstop1 ( start1LL! The inner product is (n$ut(tr startE, n ;%$e initialJalue) the value ai b i initialValue - where ai and bi denote the ith

i =1

elements of the first and second ran&e!


bool le+i*ogra$hi*alL*om$are((n$ut(tr (n$ut(tr (n$ut(tr (n$ut(tr (n$ut(tr lo'erLbound((n$ut(tr start, (n$ut(tr sto$, *onst ;%$e? elem) (n$ut(tr ma+Lelement((n$ut(tr start, (n$ut(tr sto$) (n$ut(tr minLelement((n$ut(tr start, (n$ut(tr sto$) s8, sE, t8, tE)

Feturns whether the ran&e of elements defined #y N s8- sEL is le)ico&raphically less than Nt8- tELQ that is- if the first ran&e precedes the second in a 4dictionary orderin&!6 Feturns an iterator to the first element &reater than or e5ual to the element elem in the sorted ran&e N start- sto$L! 'f you need to use a special comparison function- you can specify it as the final parameter! Feturns an iterator to the lar&est value in the ran&e N start- sto$L! 'f you need to use a special comparison function- you can specify it as the final parameter! Feturns an iterator to the smallest value in the ran&e Nstart- sto$L! 'f you need to use a special comparison functionyou can specify it as the final parameter!

bool ne+tL$ermutation(Pidir(tr start, 3iven a ran&e of elements N start- sto$L- modifies the ran&e to Pidir(tr sto$) contain the ne)t le)ico&raphically hi&her permutation of those

elements! The function then returns whether such a permutation could #e found! 't is common to use this al&orithm in a do ... 'hile loop to iterate over all permutations of a ran&e of data- as shown here=
sort(range.begin(), range.end()); do { "3 ... $ro*ess ... 3" #'hile(ne+tL$ermutation(range.begin(), range.end())); bool $revL$ermutation(Pidir(tr start, 3iven a ran&e of elements N start- sto$L- modifies the ran&e to Pidir(tr sto$) contain the ne)t le)ico&raphically lower permutation of those

elements! The function then returns whether such a permutation could #e found!
void randomLshuffle(Iandom(tr start, Iandom(tr sto$)

Fandomly reorders the elements in the ran&e Nstart- sto$L!

1 1E0 1
&or'ard(tr remove(&or'ard(tr start, &or'ard(tr sto$, *onst ;%$e? value)

Chapter <& ,TL Algorithms


Femoves all elements in the ran&e N start- sto$L that are e5ual to value! This function will not remove elements from a container! To shrink the container- use the container's erase function to erase all values in the ran&e NretJalue- end()L- where retJalue is the return value of remove! Femoves all elements in the ran&e N start- sto$L for which fn returns true! See remove for information a#out how to actually remove elements from the container!

&or'ard(tr removeLif(&or'ard(tr start, &or'ard(tr sto$, <redi*ate&un* fn)

void re$la*e(&or'ard(tr start, Feplaces all values in the ran&e Nstart- sto$L that are e5ual to &or'ard(tr sto$, toIe$la*e with re$la*e2ith! *onst ;%$e? toIe$la*e, *onst ;%$e? re$la*e2ith) void re$la*eLif(&or'ard(tr start, Feplaces all elements in the ran&e Nstart- sto$L for which fn &or'ard(tr sto$, returns true with the value 'ith! <redi*ate&un*tion fn, *onst ;%$e? 'ith) &or'ard(tr rotate(&or'ard(tr start, &or'ard(tr middle, &or'ard(tr sto$)

Fotates the elements of the container such that the se5uence Nmiddle- sto$L is at the front and the ran&e N start- middleL &oes from the new middle to the end! rotate returns an iterator to the new position of start! Feturns whether the se5uence NstartE- sto$EL is a su#se5uence of the ran&e Nstart8- sto$8L! To compare elements #y a special comparison function- specify it as a final parameter! Stores all elements that are in the sorted ran&e N start8- sto$8L #ut not in the sorted ran&e N startE- sto$EL in the destination pointed to #y dest! 'f the elements are sorted accordin& to a special comparison function- you can specify the function as the final parameter! Stores all elements that are in #oth the sorted ran&e Nstart8- sto$8L and the sorted ran&e NstartE- sto$EL in the destination pointed to #y dest! 'f the elements are sorted accordin& to a special comparison function- you can specify the function as the final parameter! Stores all elements that are in either the sorted ran&e Nstart8- sto$8L or in the sorted ran&e NstartE- sto$EL in the destination pointed to #y dest! 'f the elements are sorted accordin& to a special comparison function- you can specify the function as the final parameter! Stores all elements that are in the sorted ran&e N start8- sto$8L or in the sorted ran&e NstartE- sto$EL- #ut not #oth- in the destination pointed to #y dest! 'f the elements are sorted accordin& to a special comparison function- you can specify the function as the final parameter! Swaps the values of one and t'o! Swaps each element in the ran&e Nstart8- sto$8L with the correspond elements in the ran&e startin& with startE!

&or'ard(tr sear*h(&or'ard(tr &or'ard(tr &or'ard(tr &or'ard(tr

start8, sto$8, startE, sto$E)

(n$ut(tr setLdifferen*e( (n$ut(tr start8, (n$ut(tr sto$8, (n$ut(tr startE, (n$ut(tr sto$E, =ut(tr dest) (n$ut(tr setLinterse*tion( (n$ut(tr start8, (n$ut(tr sto$8, (n$ut(tr startE, (n$ut(tr sto$E, =ut(tr dest) (n$ut(tr setLunion( (n$ut(tr start8, (n$ut(tr sto$8, (n$ut(tr startE, (n$ut(tr sto$E, =ut(tr dest) (n$ut(tr setLs%mmetri*Ldifferen*e( (n$ut(tr start8, (n$ut(tr sto$8, (n$ut(tr startE, (n$ut(tr sto$E, =ut(tr dest) void s'a$(Jalue? one, Jalue? t'o) &or'ard(tr s'a$Lranges(&or'ard(tr start8, &or'ard(tr sto$8, &or'ard(tr startE)

Chapter <& ,TL Algorithms


=ut$ut(tr transform((n$ut(tr start, (n$ut(tr sto$, =ut$ut(tr dest, &un*tion fn) Iandom(tr

1 1E1 1
,pplies the function fn to all of the elements in the ran&e Nstart- sto$L and stores the result in the ran&e #e&innin& with dest! The return value is an iterator one past the end of the last value written! Feturns an iterator to the first element in the sorted ran&e final parameter!

u$$erLbound(Iandom(tr start, Nstart- sto$L that is strictly &reater than the value val! 'f you Iandom(tr sto$, need to specify a special comparison function- you can do so as the *onst ;%$e? val)

A 1ord on Com+atibilit/ The ST is 'SG1standardized alon& with the rest of C++! 'deally- this would mean that all ST implementations are uniform and that C++ code that works on one compiler should work on any other compiler! Unfortunately- this is not the case! "o compilers on the market fully adhere to the standard- and almost universally compiler writers will make minor chan&es to the standard that decrease porta#ility! Consider- for e)ample- the 5onvert;o7o'er5ase function from earlier in the section=
string 5onvert;o7o'er5ase(string te+t) { transform(te+t.begin(), te+t.end(), te+t.begin(), tolo'er); return te+t; #

This code will compile in Bicrosoft Tisual Studio- #ut not in Icode or the popular inu) compiler &++! The reason is that there are two tolo'er functions ( the ori&inal C tolo'er function e)ported #y **t%$e) and a more modern tolo'er function e)ported #y the lo*ale) header! Unfortunately- Icode and &++ cannot differentiate #etween the two functions- so the call to transform will result in a compiler error! To fi) the pro#lem- you must e)plicitly tell C++ which version of tolo'er you want to call as follows=
string 5onvert;o7o'er5ase(string te+t) { transform(te+t.begin(), te+t.end(), te+t.begin(), 44tolo'er); return te+t; #

/ere- the stran&e1lookin& 44 synta) is the scope"resolution operator and tells C++ that the tolo'er function is the ori&inal C function rather than the one e)ported #y the lo*ale) header! Thus- if you're usin& Icode or &++ and want to use the functions from **t%$e)- you'll need to add the 44! ,nother spot where compati#ility issues can lead to trou#le arises when usin& ST al&orithms with the ST set! Consider the followin& code snippet- which uses fill to overwrite all of the elements in an ST set with the value 1@D=
fill(m%6et.begin(), m%6et.end(), 8CD);

This code will compile in Tisual Studio- #ut will not under &++! Fecall from the second chapter on ST containers that manipulatin& the contents of an ST set in1place can destroy the set's internal orderin&! Tisual Studio's implementation of set will nonetheless let you modify set contents- even in situations like the a#ove where doin& so is unsafe! &++- however- uses an ST implementation that treats all set iterators as read1only! Conse5uently- this code won't compile- and in fact will cause some particularly nasty compiler errors! 0hen portin& C++ code from one compiler to another- you mi&ht end up with ine)plica#le compiler errors! 'f you find some interestin& C++ code online that doesn't work on your compiler- it doesn't necessarily

1 1E; 1

Chapter <& ,TL Algorithms

mean that the code is invalidQ rather- you mi&ht have an overly strict compiler or the online code mi&ht use an overly lenient one! )*tended )*am+le8 !alindromes A man, a plan, a caret, a ban, a myriad, a sum, a lac, a liar, a hoop, a pint, a catalpa, a gas, an oil, a bird, a yell, a vat, a caw, a pa4, a wag, a ta4, a nay, a ram, a cap, a yam, a gay, a tsar, a wall, a car, a luger, a ward, a bin, a woman, a vassal, a wol$, a tuna, a nit, a pall, a $ret, a watt, a bay, a daub, a tan, a cab, a datum, a gall, a hat, a tag, a 8ap, a say, a !aw, a lay, a wet, a gallop, a tug, a trot, a trap, a tram, a torr, a caper, a top, a ton*, a toll, a ball, a $air, a sa4, a minim, a tenor, a bass, a passer, a capital, a rut, an amen, a ted, a cabal, a tang, a sun, an ass, a maw, a sag, a !am, a dam, a sub, a salt, an a4on, a sail, an ad, a wadi, a radian, a room, a rood, a rip, a tad, a pariah, a revel, a reel, a reed, a pool, a plug, a pin, a pee*, a parabola, a dog, a pat, a cud, a nu, a $an, a pal, a rum, a nod, an eta, a lag, an eel, a bati*, a mug, a mot, a nap, a ma4im, a mood, a lee*, a grub, a gob, a gel, a drab, a citadel, a total, a cedar, a tap, a gag, a rat, a manor, a bar, a gal, a cola, a pap, a yaw, a tab, a ra!, a gab, a nag, a pagan, a bag, a !ar, a bat, a way, a papa, a local, a gar, a baron, a mat, a rag, a gap, a tar, a decal, a tot, a led, a tic, a bard, a leg, a bog, a burg, a *eel, a doom, a mi4, a map, an atom, a gum, a *it, a baleen, a gala, a ten, a don, a mural, a pan, a $aun, a ducat, a pagoda, a lob, a rap, a *eep, a nip, a gulp, a loop, a deer, a leer, a lever, a hair, a pad, a tapir, a door, a moor, an aid, a raid, a wad, an alias, an o4, an atlas, a bus, a madam, a !ag, a saw, a mass, an anus, a gnat, a lab, a cadet, an em, a natural, a tip, a caress, a pass, a baronet, a minima4, a sari, a $all, a ballot, a *not, a pot, a rep, a carrot, a mart, a part, a tort, a gut, a poll, a gateway, a law, a !ay, a sap, a 8ag, a tat, a hall, a gamut, a dab, a can, a tabu, a day, a batt, a water$all, a patina, a nut, a $low, a lass, a van, a mow, a nib, a draw, a regular, a call, a war, a stay, a gam, a yap, a cam, a ray, an a4, a tag, a wa4, a paw, a cat, a valley, a drib, a lion, a saga, a plat, a catnip, a pooh, a rail, a calamus, a dairyman, a bater, a canal > Panama. ( 2an /oey NCic<6O 't is fittin& to conclude our whirlwind tour of the ST with an e)ample showcasin& e)actly how concise and powerful well1written ST code can #e! This e)ample is shorter than the others in this #ook- #ut should nonetheless illustrate how the different li#rary pieces all fit to&ether! Gnce you've finished readin& this chapter- you should have a solid understandin& of how the ST and streams li#raries can come to&ether #eautifully to ele&antly solve a pro#lem! !alindromes , palindrome is a word or phrase that is the same when read forwards or #ackwards- such as 4racecar 6 or 4Balayalam!6 't is customary to i&nore spaces- punctuation- and capitalization when readin& palindromesso the phrase 4Br! Gwl ate my metal worm6 would count as a palindrome- as would 43o han& a salamiR ''m a lasa&na ho&!6 Suppose that we want to write a function (s<alindrome that accepts a string and returns whether or not the strin& is a palindrome! 'nitially- we'll assume that spaces- punctuation- and capitalization are all si&nificant in the strin&- so 4Carty trap6 would not #e considered a palindrome- thou&h 4Cart y traC6 would! 2on't worry ( we'll loosen this restriction in a #it! "ow- we want to verify that the strin& is the same when read forwards and #ackwards! There are many possi#le ways to do this! Crior to learnin& the ST - we mi&ht have written this function as follows=

Chapter <& ,TL Algorithms


bool (s<alindrome(string in$ut) { for(int B = 0; B in$ut.siUe() " E; !!B) if(in$ut[B] 1= in$ut[in$ut.length() - 8 Q B]) return false; return true; #

1 1E@ 1

That is- we simply iterate over the first half of the strin& checkin& to see if each character is e5ual to its respective character on the other half of the strin&! There's nothin& wron& with the approach- #ut it feels too mechanical! The hi&h1level operation we're modelin& asks whether the first half of the strin& is the same forwards as the second half is #ackwards! The code we've written accomplishes this task- #ut has to e)plicitly walk over the characters from start to finish- manually checkin& each pair! Usin& the ST - we can accomplish the same result as a#ove without e)plicitly spellin& out the details of how to check each character! There are several ways we can harness the ST to solve this pro#lem! 8or e)ample- we could use the ST reverse al&orithm to create a copy of the strin& in reverse order- then check if the strin& is e5ual to its reverse! This is shown here=
bool (s<alindrome(string in$ut) { string reversed = in$ut; reverse(in$ut.begin(), in$ut.end()); return reversed == in$ut; #

This approach works- #ut re5uires us to create a copy of the strin& and is therefore less efficient than our ori&inal implementation! Can we somehow emulate the functionality of the initial for loop usin& iterators> The answer is yes- thanks to reverseLiterators! Jvery ST container class e)ports a type reverseLiterator which is similar to an iterator e)cept that it traverses the container #ackwards! $ust as the begin and end functions define an iterator ran&e over a container- the rbegin and rend functions define a reverseLiterator ran&e spannin& a container! et's also consider the the ST e[ual al&orithm! e[ual accepts three inputs ( two iterators delineatin& a ran&e and a third iterator indicatin& the start of a second ran&e ( then returns whether the two ran&es are e5ual! Com#ined with reverseLiterators- this yields the followin& one"line implementation of (s<alindrome=
bool (s<alindrome(string in$ut) { return e[ual(in$ut.begin(), in$ut.begin() ! in$ut.siUe() " E, in$ut.rbegin()); #

This is a remarka#ly simple approach that is identical to what we've written earlier #ut much less ver#ose! Gf course- it doesn't correctly handle capitalization- spaces- or punctuation- #ut we can take care of that with only a few more lines of code! et's #e&in #y strippin& out everythin& from the strin& e)cept for alpha#etic characters! 8or this task- we can use the ST removeLif al&orithm- which accepts as input a ran&e of iterators and a predicate- then modifies the ran&e #y removin& all elements for which the predicate returns true! ike its partner al&orithm remove- removeLif doesn't actually remove the elements from the se5uence Ksee the last chapter for more detailsL- so we'll need to erase the remainin& elements afterwards! 7ecause we want to eliminate all characters from the strin& that are not alpha#etic- we need to create a predicate function that accepts a character and returns whether it is not a letter! The header file

1 1EA 1

Chapter <& ,TL Algorithms

**t%$e) e)ports a helpful function called isal$ha that returns whether a character is a letter! This is the opposite what we want- so we'll create our own function which returns the ne&ation of isal$ha=P bool (sKotAl$ha(*har *h) { return 1isal$ha(*h); #

0e can now strip out nonalpha#etic characters from our input strin& as follows=
bool (s<alindrome(string in$ut) { in$ut.erase(removeLif(in$ut.begin(), in$ut.end(), (sKotAl$ha), in$ut.end()); return e[ual(in$ut.begin(), in$ut.begin() ! in$ut.siUe() " E, in$ut.rbegin()); #

8inally- we need to make sure that the strin& is treated case1insensitively- so inputs like 4F,CJcar6 are accepted as palindromes! Usin& the code developed in the chapter on al&orithms- we can convert the strin& to uppercase after strippin& out everythin& e)cept characters- yieldin& this final version of (s<alindrome=
bool (s<alindrome(string in$ut) { in$ut.erase(removeLif(in$ut.begin(), in$ut.end(), (sKotAl$ha), in$ut.end()); transform(in$ut.begin(), in$ut.end(), in$ut.begin(), 44tou$$er); return e[ual(in$ut.begin(), in$ut.begin() ! in$ut.siUe() " E, in$ut.rbegin());

# This function is remarka#le in its ele&ance and terseness! 'n three lines o$ code we've stripped out all of the characters in a strin& that aren't letters- converted what's left to upper case- and returned whether the strin& is the same forwards and #ackwards! This is the ST in action- and ' hope that you're #e&innin& to appreciate the power of the techni5ues you've learned over the past few chapters! 7efore concludin& this e)ample- let's consider a variant on a palindrome where we check whether the words in a phrase are the same forwards and #ackwards! 8or e)ample- 42id mom pop> Bom didR6 is a palindrome #oth with respect to its letters and its words- while 4This is this6 is a phrase that is not a palindrome #ut is a word1palindrome! ,s with re&ular palindromes- we'll i&nore spaces and punctuationso 4't's an its6 counts as a word1palindrome even thou&h it uses two different forms of the word itsHit's! The machinery we've developed a#ove works well for entire strin&sQ can we modify it to work on a word1 #y1word #asis> 'n some aspects this new pro#lem is similar to the ori&inal! 0e still to i&nore spaces- punctuation- and capitalization- #ut now need to treat words rather than letters as meanin&ful units! There are many possi#le al&orithms for checkin& this property- #ut one solution stands out as particularly &ood! The idea is as follows= 1. Clean up the input= strip out everythin& e)cept letters and spaces- then convert the result to upper case! 2. 7reak up the input into a list of words! 3. Feturn whether the list is the same forwards and #ackwards!

P 0hen we cover the

fun*tional) li#rary in the second half of this #ook- you'll see a simpler way to do this!

Chapter <& ,TL Algorithms

1 1E? 1

'n the first step- it's important that we preserve the spaces in the ori&inal input so that we don't lose track of word #oundaries! 8or e)ample- we would convert the strin& 4/ello> /elloR> /J G>6 into 4/J G /J G /J G6 instead of 4/J G/J G/J G6 so that we can recover the individual words in the second step! Usin& a com#ination of the isal$ha and iss$a*e functions from **t%$e) and the convert1 to1upper1case code used a#ove- we can preprocess the input as shown here=
bool (sKotAl$ha=r6$a*e(*har *h) { return 1isal$ha(*h) ?? 1iss$a*e(*h); # bool (s2ord<alindrome(string in$ut) { in$ut.erase(removeLif(in$ut.begin(), in$ut.end(), (sKotAl$ha=r6$a*e), in$ut.end()); transform(in$ut.begin(), in$ut.end(), in$ut.begin(), 44tou$$er); "3 ... 3" #

,t this point the strin& in$ut consists of whitespace1delimited strin&s of uniform capitalization! 0e now need to tokenize the input into individual words! This would #e tricky were it not for stringstream! Fecall that when readin& a string out of a stream usin& the stream e)traction operator K ))L- the stream treats whitespace as a delimiter! Thus if we funnel our strin& into a stringstream and then read #ack individual strin&s- we'll end up with a tokenized version of the input! Since we'll #e dealin& with an ar#itrarily1lon& list of strin&s- we'll store the resultin& list in a ve*tor string)- as shown here=
bool (s2ord<alindrome(string in$ut) { in$ut.erase(removeLif(in$ut.begin(), in$ut.end(), (sKotAl$ha=r6$a*e), in$ut.end()); transform(in$ut.begin(), in$ut.end(), in$ut.begin(), 44tou$$er); stringstream toBeniUer(in$ut); ve*tor string) toBens; "3 ... 3"

# "ow- what is the easiest way to read strin&s out of the stream until no strin&s remain> 0e could do this manually- as shown here=
bool (s2ord<alindrome(string in$ut) { in$ut.erase(removeLif(in$ut.begin(), in$ut.end(), (sKotAl$ha=r6$a*e), in$ut.end()); transform(in$ut.begin(), in$ut.end(), in$ut.begin(), 44tou$$er); stringstream toBeniUer(in$ut); ve*tor string) toBens; string toBen; 'hile(toBeniUer )) toBen) toBens.$ushLba*B(toBen); #

This code is correct- #ut it's #ulky and unsi&htly! The pro#lem is that it's *ust too mechanical! 0e want to insert all of the tokens from the stringstream into the ve*tor- #ut as written it's not clear that this is what's happenin&! 8ortunately- there is a much- much easier way to solve this pro#lem thanks to istreamLiterator! Fecall that istreamLiterator is an iterator adapter that lets you iterate over an input stream as if it were a ran&e of data! Usin& istreamLiterator to wrap the stream operations and

1 1E6 1

Chapter <& ,TL Algorithms

the ve*tor's insert function to insert a ran&e of data- we can rewrite this entire loop in one line as follows=
bool (s2ord<alindrome(string in$ut) { in$ut.erase(removeLif(in$ut.begin(), in$ut.end(), (sKotAl$ha=r6$a*e), in$ut.end()); transform(in$ut.begin(), in$ut.end(), in$ut.begin(), 44tou$$er); stringstream toBeniUer(in$ut); ve*tor string) toBens; toBens.insert(toBens.begin(), istreamLiterator string)(toBeniUer), istreamLiterator string)());

Fecall that two istreamLiterators are necessary to define a ran&e- and that an istreamLiterator constructed with no ar&uments is a special 4end of stream6 iterator! This one line of code replaces the entire loop from the previous implementation- and provided that you have some familiarity with the ST this second version is also easier to read! The last step in this process is to check if the se5uence of strin&s is the same forwards and #ackwards! 7ut we already know how to do this ( we *ust use e[ual and a reverseLiterator! Jven thou&h the ori&inal implementation applied this techni5ue to a string- we can use the same pattern here on a ve*tor string) #ecause all the container classes are desi&ned with a similar interface! Femarka#leisn't it> The final version of (s2ord<alindrome is shown here=
bool (s2ord<alindrome(string in$ut) { in$ut.erase(removeLif(in$ut.begin(), in$ut.end(), (sKotAl$ha=r6$a*e), in$ut.end()); transform(in$ut.begin(), in$ut.end(), in$ut.begin(), 44tou$$er); stringstream toBeniUer(in$ut); ve*tor string) toBens; toBens.insert(toBens.begin(), istreamLiterator string)(toBeniUer), istreamLiterator string)()); return e[ual(toBens.begin(), toBens.begin() ! toBens.siUe() " E, toBens.rbegin()); #

(ore to )*+lore 0hile this chapter lists some of the more common al&orithms- there are many others that are useful in a variety of conte)ts! ,dditionally- there are some useful CHC++ li#rary functions that work well with al&orithms! 'f you're interested in ma)imizin& your al&orithmic firepower- consider lookin& into some of these topics= 1. 2cctype:= This chapter #riefly mentioned the **t%$e) header- the C runtime li#rary's character type li#rary! **t%$e) include support for cate&orizin& characters Kfor e)ample- isal$ha to return if a character is a letter and is+digit to return if a character is a valid he)adecimal di&itL and formattin& conversions Ktou$$er and tolo'erL!

Chapter <& ,TL Algorithms

1 1ED 1

2. 2cmath:= The C mathematics li#rary has all sorts of nifty functions that perform arithmetic operations like sin- s[rt- and e+$! Consider lookin& into these functions if you want to use transform on your containers! 3. Boost Algorit.ms= ,s with most of the C++ Standard i#rary- the 7oost C++ i#raries have a whole host of useful ST al&orithms ready for you to use! Gne of the more useful 7oost al&orithm sets is the strin& al&orithms- which e)tend the functionality of the find and re$la*e al&orithms on strings from dealin& with sin&le characters to dealin& with entire strin&s! !ractice !roblems ,l&orithms are ideally suited for solvin& a wide variety of pro#lems in a small space! Bost of the followin& pro&rammin& pro#lems have short solutions ( see if you can whittle down the space and let the al&orithms do the work for youR 1. 3ive three reasons why ST al&orithms are prefera#le over hand1written loops! 2. 0hat does the Lif suffi) on an ST al&orithm indicate> 0hat a#out Ln> 3. 0hat are the five iterator cate&ories> 4. Can an input iterator #e used wherever a forward iterator is e)pected> That is- if an al&orithm re5uires a forward iterator- is it le&al to provide it an input iterator instead> 0hat a#out the other way around> . 0hy do we need ba*BLinsertLiterator and the like> That is- what would happen with the ST al&orithms if these iterator adaptors didn't e)ist> !. The distan*e function- defined in the iterator) header- takes in two iterators and returns the num#er of elements spanned #y that iterator ran&e! 8or e)ample- &iven a ve*tor int)- callin&
distan*e(v.begin(), v.end());

returns the num#er of elements in the container! Bodify the code from this chapter that prints the avera&e of the values in a file so that it instead prints the avera&e of the values in the file #etween ;? and D?! 'f no elements are in this ran&e- you should print a messa&e to this effect! .ou will need to use a com#ination of a**umulate and distan*e! $. Usin& removeLif and a custom call#ack function- write a function Iemove6hort2ords that accepts a ve*tor string) and removes all strin&s of len&th @ or less from it! This function can #e written in two lines of code if you harness the al&orithms correctly! 6. 'n n1dimensional space- the distance from a point K 41, 4;, 4@, , 4nL to the ori&in is 2 2 2 2 x 1 x 2 x 3 ... x n . 0rite a function 9istan*e;o=rigin that accepts a ve*tor double) representin& a point in space and returns the distance from that point to the ori&in! 2o not use any loops ( let the al&orithms do the heavy liftin& for you! 5+int& 2se the inner%product algorithm to compute the e4pression under the s@uare root 6

1 1EE 1

Chapter <& ,TL Algorithms

7. 0rite a function Piased6ort that accepts a ve*tor string) #y reference and sorts the ve*tor le)ico&raphically- e)cept that if the ve*tor contains the strin& 4Be 8irst-6 that strin& is always at the front of the sorted list! This may seem like a silly pro#lem- #ut can come up in some circumstances! 8or e)ample- if you have a list of son&s in a music li#rary- you mi&ht want son&s with the title 4Untitled6 to always appear at the top! 10. 0rite a function 5riti*s<i*B that accepts a ma$ string, double) of movies and their ratin&s K#etween 0!0 and 10!0L and returns a set string) of the names of the top ten movies in the ma$! 'f there are fewer than ten elements in the ma$- then the resultin& set should contain every strin& in the ma$! 5+int& Gemember that all elements in a map&string, dou'le( are stored internally as pair&string, dou'le(6 11. 'mplement the *ount al&orithm for ve*tor int)s! .our function should have the prototype
int *ount(ve*tor int)44iterator start, ve*tor int)44iterator sto$, int element) and should return the num#er of elements in the ran&e N start- sto$L that are e5ual to element!

12. Usin& the generateLn al&orithm- the rand function- and a ba*BLinsertLiterator- show how to populate a ve*tor with a specified num#er of random values! Then use a**umulate to compute the avera&e of the ran&e! 13. The median of a ran&e of data is the value that is #i&&er than half the elements in the ran&e and smaller than half the elements in a ran&e! 8or data sets with odd num#ers of elements- this is the middle element when the elements are sorted- and for data sets with an even num#er of elements it is the avera&e of the two middle elements! Usin& the nthLelement al&orithm- write a function that computes the median of a set of data! 14. Show how to use a com#ination of *o$%- istreambufLiterator- and ostreambufLiterator to open a file and print its contents to *out! 1 . Show how to use a com#ination of *o$% and iterator adapters to write the contents of an ST container to a file- where each element is stored on its own line! 1!. Suppose that you are &iven two ve*tor int)s with their elements stored in sorted order! Show how to print out the elements those ve*tors have in common in one line of code usin& the setLinterse*tion al&orithm and an appropriate iterator adaptor! 1$. , monoalphabetic substitution cipher is a simple form of encryption! 0e #e&in with the letters of the alpha#et- as shown here=
A P 5 9 E & G 0 ( _ W 7 : K = < ` I 6 ; @ J 2 R S Z

0e then scram#le these letters randomly- yieldin& a new orderin& of the alpha#et! Gne possi#ility is as follows=
W J 9 ` _ 2 A S K E & 5 7 I 0 @ R ( = G ; Z < : 6 P

This new orderin& thus defines a mappin& from each letter in the alpha#et to some other letter in the alpha#et- as shown here=

Chapter <& ,TL Algorithms


A W P J 5 9 9 ` E _ & 2 G A 0 S ( K _ E W & 7 5 : 7 K I = 0 < @ ` R I ( 6 = ; G @ ; J Z 2 < R :

1 1E< 1
S 6 Z P

To encrypt a source strin&- we simply replace each character in the strin& with its correspondin& encrypted character! 8or e)ample- the strin& 4The cookies are in the frid&e6 would #e encoded as follows=
; G 0 ; E < 5 = = > = > W ? ( @ E < 6 A A 7 I I E < ( @ K B ; G 0 ; E < & $ I I ( @ 9 C G . E <

Bonoalpha#etic su#stitution ciphers are surprisin&ly easy to #reak ( in fact- most daily newspapers include a daily puzzle that involves decipherin& a monoalpha#etic su#stitution cipher ( #ut they are still useful for low1level encryption tasks such as postin& spoilers to we#sites Kwhere viewin& the spoiler e)plicitly re5uires the reader to decrypt the te)tL! Usin& the randomLshuffle al&orithmimplement a function :onoal$habeti*6ubstitutionEn*r%$t that accepts a source strin& and encrypts it with a random monoalpha#etic su#stitution cipher!

!art Two
Data Abstraction
It)s all !ust bits and bytes! Jverythin& on your machine- whether it's your ta) return- a picture from a trip- a we# pa&e- or a we# #rowser- is stored in memory as a series of ones and zeros encoded as ma&netic- optical- or electrical si&nals! /ow- then- can a computer do word processin&> Gr view ima&es> Gr check your email> ,ll of this data has structure ( te)t documents store words and fonts- ima&es vivid color pictures- and email a mi)ture of te)t- headers- and contacts!

C.a+ter ,8 Abstraction and Classes


_________________________________________________________________________________________________________

Software keeps &ettin& #i&&er! Society keeps di&itizin& and automatin& more and more aspects of life- and the scope and comple)ity of software systems are ever increasin&! 8or computer scientists- this is a thrillin& prospect= even after decades of #oomin& &rowth- the field is still e)pandin& and applications a#ound! 7ut for software en&ineers 1 the #rave souls who actually write the code ( this can #e dauntin&! 'n the early days of pro&rammin&- software was considera#ly less complicated #ecause the tasks we used to ask of computers are nowhere near as comple) as those we ask today! Gperatin& systems worked on less powerful hardware and with considera#ly fewer peripherals! The earliest we# #rowsers didn't need to support a wide array of /TB - CSS- $avaScript- IB - ST3- and FSS formats! Tideo &ames didn't need to take advanta&e of the latest1and1&reatest @2 hardware and weren't criticized for not havin& the most up1 to1date shadin& en&ine! 7ut nowadays- the e)pectations are hi&her- and software is &rowin& more complicated! Unfortunately- increasin& the size of a software system &reatly increases the system's comple)ity and opens all sorts of avenues for failure! Com#atin& software comple)ity is therefore e)traordinarily important as it allows software systems to &row ro#ustly! This section of this #ook is dedicated entirely to techni5ues for com#atin& comple)ity throu&h a particular techni5ue called abstraction! ,#straction is a su#tle #ut important aspect of software desi&n- and in many ways the difference #etween &ood pro&rammers and e)cellent pro&rammers is the a#ility to desi&n ro#ust and intuitive a#stractions in software! Bany te)t#ooks *ump directly into a discussion of what a#straction is all a#out and how to represent it in software- #ut ' feel that doin& so o#scures the fundamental reasons underlyin& a#straction! This chapter discusses how software en&ineerin& is different from other en&ineerin& disciplines- why software comple)ity is particularly dan&erous- and how a#straction can dramatically reduce the comple)ity of a software system! 't then introduces the *lass keyword and how to represent a#straction directly in source code! T.e Com+le*it/ of 6oftware 0hat e)actly does it mean to talk a#out the comple)ity of a software system> Gne of the first metrics that may come to mind is the num#er of lines of code in the pro&ram! This is akin to measurin& the comple)ity of a chip #y the num#er of transistors on it or a #rid&e #y the num#er of welds re5uired= while in &eneral system comple)ity rises with lines of code- a pro&ram with ten thousand lines of code is not necessarily ten times more complicated than a system with one thousand lines of code! /owever- num#er of lines of code is still a reasona#le metric of software comple)ity! To &ive you a sense for how massive some pro*ects can #e- here is a list of various software pro*ects and the num#er of lines of code they contain=

1 1<A 1 1 O 11- O 1-1-- O 1I--1I--- O 1-I--1-I--- O 1--I--1--I--- O 1I---I--1I---I--- O 1-I---I--1-I---I--- O 1--I---I--1--I---I--- & 1I---I---I--/ello- 0orldR

Chapter H& Abstraction and Classes

Bost implementation of the ST sta*B or [ueue! Bost of the worked e)amples in this #ook! 'ntensive team pro*ect in a typical computer science curriculum! Bost inu) command1line utilities! inu) g!! Compiler Bozilla 8irefo) Bicrosoft 0indows ;000 Kernel 2e#ian inu) Gperatin& System

The num#er of lines of code in each of these entries is ten times more than in the previous e)ample! This means that there are ten times as many lines of code in 8irefo) than in &++- for e)ample! ,nd yes- you did read this correctly ( there are many- many pro*ects that clock in at over a million lines of code! The 2e#ian inu) kernel is rou&hly ;@0 million lines of code as of this writin&! 't's &enerally accepted that no sin&le pro&rammer can truly understand more than fifty thousand lines of code- which means that in all #ut the simplest of pro&rams- no one pro&rammer understands how the entire system works! So software is comple) ( so what> That is- why does it matter that modern software systems are &ettin& #i&&er and more complicated> There are many reasons- of which two specifically stand out! Jvery 7it Counts 'n a software system- a sin&le incorrect #it can spell disaster for the entire pro&ram! 8or e)ample- suppose you are desi&nin& a system that controls a nuclear reactor core! ,t some point in your pro&ram- you have the followin& control lo&ic=
if (:eltdo'n(n<rogress()) { 6etIea*tor<o'er(0); Emergen*%6hutoff(); #

et's suppose that :eltdo'n(n<rogress returns a bool that si&nals whether the reactor is meltin& down! Gn most systems- bools are represented as a se5uence of ones and zeros called bits! The value false is represented #y those #its all #ein& zero- and true represented #y any of the #its #ein& nonzero! 8or e)ample- the value 00080000 would #e interpreted as true- while 00000000 would #e false! This means that the difference #etween true and false is a sin&le #it! 'n the a#ove e)ample- this means that the difference #etween shuttin& down the reactor in an emer&ency and continuin& normal operation is a single bit in memory! 'n the a#ove e)ample- our 4sin&le incorrect #it6 was the difference #etween the #oolean values true and false- #ut in most systems the 4sin&le incorrect #it6 will #e somethin& else! 't mi&ht- for e)ample- #e an ne&ative inte&er where a positive inte&er was e)pected- an iterator that is past the end of a container- or an unsorted vector when the data was e)pected to #e sorted! 'n each of these cases- the erroneous data is likely to #e only a handful of #its off from a meanin&ful piece of data- #ut the result will #e the same ( the pro&ram won't work as e)pected!

Chapter H& Abstraction and Classes Interactions row )*+onentiall/

1 1<? 1

Suppose you have a pro&ram with n lines of code! et's consider an 4interaction6 to #e where data is manipulated #y two different lines of code! 8or e)ample- one interaction mi&ht #e creatin& an int in one line and then printin& it to the console in the ne)t- or a function passin& one of its parameters into another function! Since every line of code mi&ht potentially manipulate data created #y any of the other n lines of code- if you sum up this count for all n lines of code there are rou&hly n; pairs of interactin& lines! This which means that the num#er of possi#le interactions in a software pro*ect increases- in the worst case- as the s@uare of the num#er of lines of code! et's consider a sli&htly different take on this! Suppose you are workin& on a software pro*ect with n lines of code and you're interested in addin& a new feature! ,s mentioned a#ove- any chan&es you make mi&ht interact with any of the e)istin& n lines of code- and those n lines of code mi&ht interact with all of your new lines of code! 'f the chan&es you make somehow violate an assumption that e)ists in some other module- then chan&es in your relatively isolated re&ion of the code #ase mi&ht cause catastrophic failures in entirely different parts of the code #ase! /owever- the situation is far worse than this! 'n this e)ample we considered an interaction to #e an interaction #etween two lines of code! , more realistic model of interactions would consider interactions #etween arbitrarily many lines of code- since chan&es made in several different points mi&ht conver&e to&ether in a point to form a result not possi#le if a sin&le one of the chan&es didn't occur! 'n this case- if the code #ase has n lines of code- the ma)imum num#er of interactions Ksets of two or more lines of codeL is rou&hly ;n! That's a sta&&erin&ly hu&e num#er! 'n fact- if we make the li#eral assumption that there are 10100 atoms in the universe Kmost estimates put the fi&ure at much less than thisL- then even a compara#ly small software system Ksay- three thousand lines of codeL has more possi#le interactions than there are atoms in the universe! 'n short- the lar&er a software system &ets- the &reater the likelihood than an error occurs andconse5uently- the more difficult it is to make chan&es! 'n short- software is chaotic- and even minuscule chan&es to a code #ase can completely cripple the system! Abstraction Gne of the most powerful techni5ues availa#le to com#at comple)ity is abstraction- a means of simplifyin& a comple) pro&ram to a mana&ea#le level! Father than *umpin& headfirst into a full1on definition of a#straction with e)amples- let's look at a#straction #y means of an e)ample! Consider a standard- run1of1 the1mill stapler! Certainly you understand how to use a stapler= you place the papers to staple under the arm of the stapler- then depress the handle to staple the pa&es to&ether! .ou've undou#tedly encountered more than one stapler in your life- yet K#arrin& unfortunate circumstancesL you've pro#a#ly fi&ured out how to work all of them without much trou#le! Staplers come in all shapes and sizes- and conse5uently have many different internal mechanisms- yet switchin& from one type of stapler to another poses little to no pro#lem to you! 'n fact- you pro#a#ly don't think much a#out staplers- even when you're usin& them! "ow consider the companies that make staplers ( Swin&line or Bc3ill- for e)ample! These companies e)pend millions of dollars desi&nin& pro&ressively #etter staplers! They consider all sorts of tradeoffs #etween different types of sprin&s and different construction materials! 'n fact- they pro#a#ly e)pend more effort in a sin&le day desi&nin& staplers than you will ever spend thinkin& a#out staplers in your entire life! 7ut nonetheless- at the end of the day- staplers are simple and easy to use and #ear no markin&s to indicate the painstakin& la#or that has &one into perfectin& them! This setup- where a dedicated manufacturer desi&ns a comple) #ut easy1to1use product- is the heart of a#straction!

1 1<6 1

Chapter H& Abstraction and Classes

8ormally speakin&- an abstraction is a description of an o#*ect that omits all #ut a few salient details! 8or e)ample- suppose we want to descri#e a particular coffee mu&! /ere are several different descriptions of the coffee mu&- each at different levels of a#straction= Batter! ,n o#*ect! , #evera&e container! , coffee mu&! , white coffee mu&! , white ceramic coffee mu&! , white ceramic coffee mu& with a small crack in the handle! , white ceramic coffee mu& with a small crack in the handle whose manufacturer's lo&o is em#lazoned on the #ottom!

"otice how these descriptions move from least specific KmatterL to most specific K, white ceramic coffee mu& with a small crack in the handle whose manufacturer's lo&o is em#lazoned on the #ottomL! Jach of the descriptions descri#e the same coffee mu&- #ut each does so at a different level of detail! 2ependin& on the circumstance- different levels of detail mi&ht #e appropriate! 8or e)ample- if you were a physicist interested in modelin& universal &ravitation- the fact that the coffee mu& is made of matter mi&ht #e sufficient for your purposes! /owever- if you wanted to paint a picture of the mu&- you would pro#a#ly want to pick the last description- since it offers the most detail! 'f you'll notice- as the descriptions #ecome more and more detailed- more and more information is revealed a#out the o#*ect! Startin& from the first of these descriptions and movin& downward- the picture of the coffee mu& #ecomes more clear! 2escri#in& the coffee mu& as 4matter6 hardly helps you picture the mu&- #ut as you &o down the list you #e&in to notice that the mu& is white- has a small crack- and has a lo&o printed on the #ottom! 0hat does this have to do with our previous discussion on staplers> The answer is simple= the reason that staplers are so easy to use despite the comple) mechanisms that make them work is #ecause the very notion of a stapler is an a#straction! There are many ways to #uild a stapler- some of which have handles to staple documents- and others which use pro)imity sensors to detect paper and insert the staples automatically! ,lthou&h these devices have little mechanism or structure in common- we would consider #oth of them staplers #ecause they staple paper! 'n other words- what is important to us as stapler users is the fact that staplers fasten paper to&ether- not their inner workin&s! This may seem like a stran&e line of reasonin&- #ut it's one of the sin&le most important concepts to &rasp as a computer scientist! The rest of this chapter is dedicated to e)plorin& what a#straction means from a pro&rammin& perspective and how a#straction can com#at comple)ity! 7ut first- let's discuss some of the ma*or concepts and terms pertainin& to a#straction at a hi&h level! T.e 1all of Abstraction 'n our previous e)ample with staplers- there was a clear separation of comple)ity #etween the stapler manufacturer and the end user! The manufacturer took painstakin& care to ensure that the stapler works correctly- and end users *ust press a handle or feed paper near a sensor! This separation is fundamental to com#atin& comple)ity- and is &iven an appropriately impressive name= the wall o$ abstraction! The wall of a#straction is the information #arrier #etween a device and how it wor*s! Gn one side of the wall is the manu$acturer- whose task is to provide a device capa#le of meetin& certain re5uirements! To the manufacturer- the sin&le most important task is producin& a device that works correctly and relia#ly! Gn the other side of the wall of a#straction is the end user- who is interested in usin& the device #ut whounless curious- does not particularly care how the device works! 'n computer science- we refer to these two roles as the client- who uses the device- and the implementer- who is tasked with makin& it work correctly!

Chapter H& Abstraction and Classes

1 1<D 1

0hen usin& a stapler- you don't care how the stapler works #ecause it's an unnecessary mental #urden! .ou shouldn't need to know what type of metal the casin& is made from- nor should you have to worry a#out what type of sprin& pushes the staples up to the front of the stapler! The same is true of almost every device and appliance in use today! 2o you know e)actly how a microwave works> /ow a#out an internal com#ustion en&ine> 0hat a#out an iChone> Jach of these devices is e)traordinarily complicated and works on nuanced principles of physics- materials science- chemical en&ineerin&- and in some cases electrical and software en&ineerin&! The ma&ic of all of these devices is that we don)t need to *now how they wor*! 0e can trust that a team of dedicated en&ineers understand their inner workin&s- and can focus instead on usin& them! The fact that the wall of a#straction separates the implementer in the client necessarily means that an a#straction shields clients from unnecessary implementation details! 'n that sense- the wall of a#straction is a #arrier that prevents information a#out the device's internals from leakin& outside! That the wall of a#straction is an information #arrier has profound conse5uences for software desi&n! 7efore we discuss how a#straction can reduce system comple)ity- let us focus on this aspect in more detail! Abstractions are Im+recise Jarlier in this chapter we discussed a#straction in the conte)t of a coffee mu& #y e)plorin& descriptions of a cof fee mu& at various levels of a#straction! Suppose that we have an actual coffee mu& we are interested in desi&nin& an a#straction forQ for e)ample- this mu& here=

The hi&hest1level description of a coffee mu& in the ori&inal list was the e)traordinarily va&ue 4matter!6 That is- all of the properties of the coffee mu& are i&nored e)cept for the fact that it is matter! This means the implementer KusL holds a coffee mu&- #ut the client Kthe person readin& the description 4matter6L knows only that our o#*ect is composed of matter! 7ecause the wall of a#straction prevents information from leakin& to the client- that our o#*ect is made of matter is the only information the client has a#out the coffee mu&! This means that the client can't tell if our o#*ect is a coffee mu&- $upiter's moon 3anymede- or a fried e&&! 'n other words- our description was so va&ue that the client knows nothin& a#out what o#*ect we have! et's now move to a lower level of a#straction- the description that the mu& is 4a #evera&e container!6 The client can now tell that our mu& is not 3anymede- nor is it a fried e&&- #ut we haven't yet e)cluded other possi#ilities! Bany thin&s are #evera&e containers ( punch #owls- wine &lasses- thermoses- etc! ( and the client cannot fi&ure out from our limited description that the o#*ect is a coffee mu&! /owever- without knowin& that the o#*ect is a coffee mu&- at this level of a#straction the client could safely assume that our o#*ect could store water!

1 1<E 1

Chapter H& Abstraction and Classes

"ow let's consider an even more precise description= we descri#e the coffee mu& as 4a coffee mu&!6 "ow what can the client infer a#out our mu&> 7ecause we have said that the o#*ect is a mu&- they know that it's a coffee mu&- true- #ut there are many properties of the o#*ect that they don't know! 8or e)ample- how #i& is the mu&> 0hat color is it> 0hat desi&n- if any- adorns the mu&> , client on the other side of the wall of a#straction still can't paint a particularly vivid picture of the mu& we're descri#in&- #ut they now know a &ood deal more a#out the mu& than they did with either of the two previous descriptions! This a#ove discussion hits on a ma*or point= a#stractions are imprecise! 0hen descri#in& the coffee mu& at various levels of detail- we always truthfully represented our coffee mu&- #ut our descriptions never were sufficient to unam#i&uously convince the client of what o#*ect we were descri#in&! 'n fact- if we had instead #een descri#in& a different coffee mu&- like this one here=

then all of our descriptions would still have #een perfectly honest! ,#stractions- #y their very nature- make it impossi#le for the client to know e)actly what o#*ect is #ein& descri#ed! This is an incredi#le #lessin&! Suppose- for e)ample- that you #rin& your car in for routine maintenance! The mechanic informs you that your radiator is nearin& the end of its lifespan- so you pay for a replacement! Gnce the mechanic replaces the radiator and you drive off into the sunset- the car that you are drivin& is not the same car that you drove in with! Gne of its fundamental components has #een replaced- and so an inte&ral part of the car's system is not the same as it used to #e! /owever- you feel like you are drivin& the same car when you leave #ecause from your perspective- nothin& has chan&ed! The accelerator and #rakes still work as they used to- the car handles like it used to- and in fact almost every maneuver you perform with the car will e)ecute e)actly the same way that the car used to! Tiewin& this idea throu&h the lens of a#straction- the reason for this is that your conception of the car has to do with its o#serva#le #ehavior! The car you are now drivin& has a different 4implementation6 than the ori&inal car#ut it adheres to the same a#straction as the old car and is conse5uently indistin&uisha#le from the ori&inal car! 0ithout lookin& under the hood K#reakin& the wall of a#stractionL- you wouldn't #e a#le to notice the difference! Interfaces The wall of a#straction sits at the #oundary #etween two worlds ( the world of the implementer- where the workin&s of the mechanism are of paramount importance- and the world of the client- where the o#serva#le #ehavior is all that matters! ,s mentioned earlier- the wall of a#straction is an information #arrier that prevents implementation details and usa&e information from crossin& #etween the client and implementer! 7ut if the client is unaware of the implementation of the particular device- how can she possi#ly use it> That is- if there is a lo&ical #arrier #etween the two parties- how can the client actually use the implementer's device>

Chapter H& Abstraction and Classes

1 1<< 1

Gne typical way to provide the client access to the implementation is via an inter$ace! ,n interface is a set of commands and 5ueries that can #e e)ecuted on the device- and is the way that the client interacts with the o#*ect! 8or e)ample- an interface mi&ht let the client learn some properties of the o#*ect in 5uestion- or mi&ht allow the client to ask the device to perform some task! 'n software en&ineerin&- an interface typically consists of a set of attri#utes Kalso called propertiesL that the o#*ect is re5uired to have- alon& with a set of actions that the o#*ect can perform! 8or e)ample- here's one possi#le interface for a stapler= ,ttri#utes= "um#er of staples left! Size of staples #ein& used! /ow many sheets of paper are in the stapler! The ma)imum num#er of sheets of paper that the stapler can staple! ,ctions= ,dd more staples! Cut paper into the stapler! Staple the papers to&ether!

'nterfaces are fascinatin& #ecause they provide a particularly ele&ant means for a implementer to e)pose an o#*ect to a client! The implementer is free to #uild the device in 5uestion as she sees fit- provided that all of the operations specified in the interface work correctly! That is- someone implementin& a stapler that adheres to the a#ove interface can use whatever sort of mechanism they feel like to #uild the staplerso lon& as it is possi#le to look up how many staples are left- to add more staples to the stapler- etc! Similarly- the client needs only learn the operations in the interface and should KtheoreticallyL #e a#le to use any device that conforms to that interface! 'n software en&ineerin& terminolo&y- we say that the implementer implements the interface #y providin& a means of transformin& any re5uest &iven to the interface to a re5uest to the underlyin& device! 8or e)ample- if the Swin&line corporation decided to create a new stapler- they mi&ht #uild a concrete stapler and then implement the interface for staplers as follows= ,ttri#utes= "um#er of staples left= $+en t.e co;er and count t.e number of sta+les. Size of staples #ein& used= $+en t.e co;er and look at t.e si5e of t.e sta+les. /ow many sheets of paper are in the stapler= Count t.e s.eets of +a+er on t.e base +late. The ma)imum num#er of sheets of paper that the stapler can staple= 2# ,ctions= ,dd more staples= $+en t.e co;er and insert more sta+les. Cut paper into the stapler= !lace t.e +a+er o;er t.e base +late! Staple the papers to&ether= De+ress t.e .andle until it clicksI t.en release t.e .andle.

/owever- we could also implement the stapler inteface in a different way if we were usin& an electronic stapler= ,ttri#utes= "um#er of staples left= 4ead t.e digital dis+la/! Size of staples #ein& used= 4ead t.e digital dis+la/! /ow many sheets of paper are in the stapler= 4ead t.e digital dis+la/! The ma)imum num#er of sheets of paper that the stapler can staple= 7# ,ctions= ,dd more staples= $+en t.e co;er and sna+ t.e new roll of sta+les in +lace! Cut paper into the stapler= !lace t.e +a+er into t.e loading assembl/! Staple the papers to&ether= !ress t.e Psta+leQ button!

1 ;00 1

Chapter H& Abstraction and Classes

"otice that these two staplers have the same interface #ut entirely different actions associated with each item in the interface! This is a concrete e)ample of a#straction in action 1 #ecause the interface only descri#es some specific attri#utes and actions associated with the stapler- anythin& that can make these actions work correctly can #e treated as a stapler! The actual means #y which the interface is implemented may #e different- #ut the &eneral principle is the same! ,n e)tremely important point to note is the relation #etween interfaces and a#stractions! ,#straction is a &eneral term that descri#es how to simplify systems #y separatin& the role of the client and the implementer! 'nterfaces are the means #y which a#stractions are actually modeled in software systems! 0henever one speaks of a#straction in pro&rammin&- it usually refers to desi&nin& an interface! 'n other words- an o#*ect's interface is a concrete description of the a#straction provided for that o#*ect! )nca+sulation 0hen workin& with interfaces and a#stractions- we #uild a wall of a#straction to prevent implementation details a#out an o#*ect from leakin& to the client! This means that the client does not necessarily need to know how the particular o#*ect is implemented- and can *ust rely on the fact that some implementer has implemented the interface correctly! 7ut while an interface captures the idea that a client doesn't have to know the particular implementation details- it does not e)press the idea that a client shouldn)t know the particular implementation details! To understand this- let's return to our discussion of staplers! 'f an implementer provides a particular stapler that implements the stapler interface- then anyone usin& that stapler can *ust use the interface to the stapler to &et all of their re5uired functionality! /owever- there's nothin& stoppin& them from disassem#lin& the stapler- lookin& at its component parts- etc! 'n fact- &iven a physical stapler- it's possi#le to do thin&s with that stapler that weren't initially anticipated! .ou could- for e)ample- replace the stapler handle with a pneumatic compressor to #uild a stapler &un- which mi&ht make the stapler more efficient in a particular application! /owever- you could also remove the sprin& inside the stapler which forces the staples to the front of the staple tray- renderin& the stapler useless! 'n &eneral- allowin& clients to #ypass interfaces and directly modify the o#*ect descri#ed #y that interface is dan&erous! The entire purpose of an interface is to let implementers #uild ar#itrarily complicated systems that can #e operated simply- and if a client #ypasses the interface he'll #e dealin& with an o#*ect whose workin&s could easily #e far #eyond his comprehension! 'n the case of a stapler- #ypassin& the interface and lookin& at the stapler internals isn't likely to cause any pro#lems- #ut you would certainly #e askin& for trou#le if you were to start pokin& around the internals of the Space Shuttle! This violationwhere a client #ypasses an interface- is called brea*ing the wall o$ abstraction! The a#ove e)amples have hinted at why #reakin& the wall of a#straction is a #ad idea- #ut we haven't e)plicitly spelled out any reasons why in &eneral it can #e dan&erous! et us do this now! 8irst- #reakin& the wall of a#straction allows clients to severely hurt themselves #y tweakin& a comple) system! 'n a comple) system like a car en&ine- certain assumptions have to hold a#out the relationship #etween the parts of the car in order for the car to work correctly! That is- fuel shouldn't #e in*ected into the en&ine e)cept in certain parts of the cycle- the transmission shouldn't try shiftin& &ears until the clutch has #een released- etc! Conse5uently- most cars provide an interface into the en&ine that consists of a &as and #rake pedal- whose operation controls all of the relevant parts of the en&ine! 'f you were to i&nore these controls and instead try to drive the car #y manually ad*ustin& fuel intake and the #rake pressure- #arrin& special trainin&- you would almost certainly either cause an e)plosion or irreversi#ly destroy the en&ine! Femem#er that a#straction protects #oth the client and the implementer ( the client doesn't need to know a#out the inner workin&s of the o#*ect- and the implementer doesn't need to worry that the client can make ar#itrary chan&es to the o#*ectQ all operations on the o#*ect must come throu&h the interface! 7reakin& the wall of a#straction violates #oth these assumptions and can hurt #oth parties! The second ma*or reason a&ainst #reakin& the wall of a#straction is to ensure system fle)i#ility! ,s mentioned earlier- a#stractions are #y nature imprecise- and multiple different implementations mi&ht

Chapter H& Abstraction and Classes

1 ;01 1

satisfy a particular interface! 'f the client is allowed to #reak the wall of a#straction and look at a particular part of the implementation- then that implementation is in essence 4locked in place!6 8or e)ample- suppose that you provide a traditional stapler to a client! That client then decides to use the stapler in a conte)t where the e)act position and orientation of the stapler hin&e is importantQ perhaps the client has trained a ro#ot to use the stapler #y learnin& to feed paper into the stapler whenever the hin&e is at a particular an&le! Jarlier in this chapter- we discussed how interfaces make it possi#le to chan&e an o#*ect's implementation without #efuddlin& the user! That is- if the client only uses the operations listed in an interface- then any o#*ect implementin& that interface should #e su#stituta#le for any other! The pro#lem with #reakin& the wall of a#straction is that this is no lon&er possi#le! Consider- for e)amplewhat happens if we try to replace the mechanical stapler from this setup with an electric stapler! Jlectric staplers tend not to have hin&es- and so if we swapped staplers the ro#ot desi&ned to feed paper into the stapler would no lon&er #e a#le to insert paper! 'n other words- #ecause the ro#ot assumed that some property held true of the implementation that was documented nowhere in the interface- it #ecame impossi#le to ever chan&e the implementation! To summarize ( peerin& #ehind an interface and lookin& at the underlyin& implementation is a #ad idea! 't allows clients to poke systems in ways that were never intended- and it locks the particular implementation in place! 'f an a#straction does not allow clients to look at the implementation under any circumstance- that a#straction is said to #e encapsulated! 'n other words- it is as thou&h the actual implementation is trapped inside a &iant capsule- and the only way to access the o#*ect is #y issuin& 5ueries and commands specified #y the interface! Jncapsulation is uncommon in the real world- #ut some analo&ies e)ist! 8or e)ample- if you visit a rare #ook collection- you cannot *ust &o in and take any #ook off the shelf! 'nstead- you have to talk to a li#rarian who will then &et the #ook for you! .ou have no idea where the #ook comes from ( perhaps it's sittin& on a shelf in the #ack- or perhaps the li#rarian has to &et a courier to fetch it from some special vault ( #ut this doesn't concern you #ecause at the end of the day you KhopefullyL have the #ook anyway! Jncapsulated interfaces are e)traordinarily important in software #ecause they represent a means for entirely containin& comple)ity! The immense amount of implementation detail that mi&ht #e necessary to implement an interface is a#stracted away into a small set of commands that can #e e)ecuted on that interface- and encapsulation prevents other parts of the pro&ram from inadvertently Kor deli#eratelyL modifyin& the implementation in une)pected ways! ater in this chapter- when we discuss classes- you will see how C++ allows you to #uild encapsulated interfaces! T.e (at.8 1./ Abstraction 1orks 0e've talked a#out a#straction and how it lets clients operate with comple) o#*ects without knowin& their full implementation! The implicit claim throu&hout this chapter has #een that this &reatly reduces the comple)ity of software systems! ,mazin&ly- &iven a suita#le definition of system comple)ity- we can prove that increasin& the level of a#straction in a system reduces the ma)imum comple)ity possi#le in the system! 'n this discussion- we'll need to settle on a definition of a system's comple)ity! 'f a system consists of different interfaces- we will define the ma)imum comple)ity of that system to #e the ma)imum num#er of interactions #etween these interfaces! 8or our purposes- we'll consider an interaction #etween interfaces to #e a set of two or more interfaces! 't can #e shown that there are ; n ( n ( 1 possi#le interactions #etween interfaces- which is an a#solutely hu&e num#er! 'n fact- in a system with ten interfaces- there are 1-01@ possi#le interactions #etween those interfaces! The reason for this is the first term in this 5uantity K;nL- which &rows e)tremely fast! 't &rows so 5uickly that we can i&nore the last two terms in the sum and appro)imate the ma)imum comple)ity of a system as ;n!

1 ;0; 1

Chapter H& Abstraction and Classes

"ow- suppose that we introduce a new a#straction into a system that reduces the total num#er of interfaces in the system #y 10! This means that the new system has n 1 10 interfaces- and conse5uently its ma)imum comple)ity is ;n 1 10! 'f we take the ratio of the ma)imum comple)ity of the new system to the ma)imum comple)ity of the old system- we &et ; 110- which is *ust under one one1thousandth! That is- the ma)imum comple)ity of the new system will #e rou&hly one one1thousandth that of the ori&inal system! This result has e)tremely important implications for software desi&n! 't is possi#le to #uild reasona#ly simple software systems that are hundreds of millions of lines of code simply #y minimizin& the num#er of interfaces present in the software system! This caps the ma)imum comple)ity of the system #y limitin& the num#er of possi#le interactions! 7ut the a#ove lo&ic is terri#ly misleadin&! 'n practice- software systems rarely &et even close to reachin& the ma)imum num#er of possi#le interactions! Ba)imum comple)ity only occurs if every com#ination of o#*ects has a well1defined interaction- and this is rarely the case! 8or e)ample- in a simulation with a stapler- pen- and pencil sharpener- you are unlikely to ever have the stapler and pencil sharpener interactand if you do it is e)tremely unlikely that you will have all three o#*ects have some specific #ehavior when interactin& all at the same time! , more realistic measure of comple)ity is the num#er of ways in which pairs of o#*ects can interact! This is a desira#le choice for several reasons! 8irst- it corresponds to an ele&ant &raphical measure of comple)ity! 'f we list all of the components in a system and add lines #etween pairs of o#*ects that interact with each other- the comple)ity of that system is then the num#er of lines in the picture! 8or e)ample- here are two dia&rams of ways that common office supplies mi&ht interact with one another! The first system is clearly more comple) than the second since there are more interactions defined #etween the components!

Pa/+r

Sta/-+r

Pa/+r

Sta/-+r

P+n*i-

S1ar/+n+r

P+n*i-

S1ar/+n+r

S+t0/ on+2 E3+ryt1ing int+ra*t& .it1 +3+ryt1ing +-&+4

S+t0/ t.o2 On-y m+aning50int+ra*tion& d+5in+d4

Second- in practice- interactions #etween two or more o#*ects can usually #e simplified down into multiple instances of interactions #etween pairs of o#*ects! 8or e)ample- if three #illiard #alls all collide- we could consider the interaction #etween the three #alls as three separate interactions of the pairs of #alls! Gnly in unusual circumstances is such a decomposition not possi#le! 8inally- considerin& interactions only of pairs rather than of triples or 5uadruples tends to correspond more accurately to how systems are actually #uilt! 't is conceptually simpler to think a#out how a sin&le piece of a system interacts with each of its nei&h#ors in isolation than it is to think a#out how that pieces interacts with all of its nei&h#ors simultaneously! Jven with this more restrictive definition of comple)ity- reducin& the num#er of interfaces in a system still produces lar&er reductions in comple)ity! 't can #e shown that the num#er of possi#le pairs of interactin& o#*ects is sli&htly less than n;! This means that if we make a linear reduction in the num#er of o#*ects in the system- we &et a 5uadratic decrease in the ma)imum comple)ity in that system! That is- removin& ten interfaces isn't &oin& to drop the ma)imum comple)ity #y ten interactions ( it will #e a considera#ly #i&&er num#er!

Chapter H& Abstraction and Classes Classes

1 ;0@ 1

The sin&le most important difference #etween C++ and its predecessor C is the notion of a class! Classes are C++'s mechanism for encodin& and representin& a#straction- pairin& interfaces with implementationsand enforcin& encapsulation! The entire remainder of this #ook will #e dedicated to e)plorin& how to create- modify- maintain- use- and refine classes and class definitions! 'n the previous discussion on a#straction- we discussed a#stractly the notions of interfaces and encapsulation! 7efore we discuss the class mechanism- let's consider an e)tended e)ample that illustrates e)actly why a#straction and interfaces are so important! 'n particular- we will e)plore how one mi&ht represent an 8B radio tuner in C++ code! 0e won't actually create a workin& 8B radio in software ( that would re5uire specialized hardware ( #ut the e)ample should demonstrate many of the reasons why classes are so important! Designing an 2( 4adio 'n our e)ample- we will create a data structure that stores information a#out an 8B radio! Since the properties of an 8B radio can't #e represented with a sin&le varia#le- we'll create a stru*t called &:Iadio which will hold all of our data! 0hat should this stru*t contain> ,t a #are minimum- we will need to know what fre5uency the radio is tuned in to! 0e also pro#a#ly want to specify a volume control- so that listeners can turn up hi&h1ener&y music or turn down shoutin& news pundits! 0e can represent this information as follows=
stru*t &:Iadio { double fre[uen*%; int volume; #;

/ere- the fre5uency field stores the fre5uency in B/z! 8or e)ample- if you were listenin& to EE!? KMJ2 San 8rancisco- this field would have the value EE!?! Similarly- listenin& to 10D!< The Jnd Sacramento would have the field hold 10D!<! ''ve ar#itrarily chosen to store the volume as an int that holds a value #etween 0 and 10- inclusive! Tolume zero completely mutes the radio- while volume ten is as much power as the speaker can deliver! This means that if ' wanted to confi&ure my radio to listen to 4This ,merican ife6 at a reasona#ly 5uiet level- ' could write
&:Iadio m%Iadio; m%Iadio.fre[uen*% = FF.H; "" FF.H :0U (W`E9) m%Iadio.volume = C; "" Ieasonabl% [uiet

"ow- let's consider one more e)tension to the radio! Bost radios these days let the user confi&ure up to si) different 4presets-6 saved stations that listeners can ad*ust the radio to 5uickly! Bost car radios have this feature- althou&h older 8B radios do not! The presets are num#ered one throu&h si)- and at any time a particular preset mi&ht #e empty Kthe listener hasn't pro&rammed this preset yetL or set to a particular fre5uency! ,s an e)ample- ' fre5uently commute #etween Calo ,lto and Sacramento- and en*oy listenin& to "CF on the drive! 7oth Sacramento and San 8rancisco have stations that #roadcast "CF content- and a#out halfway #etween Calo ,lto and Sacramento one of the stations fades out dramatically while the other one comes in much more stron&ly! To make it easier to switch #etween the stations- ' pro&rammed my car radio's presets so that preset one is the San 8rancisco station KEE!?L and preset two is the Sacramento station KE<!@L! 0e'd like to add this functionality to 8BFadio- #ut what's the #est way to do so> 'f we want to store a list of si) different settin&s- we could do so with a ve*tor- #ut run into a pro#lem #ecause a ve*tor always enforces the restriction that there must #e an element at every position! 7ecause some of the presets

1 ;0A 1

Chapter H& Abstraction and Classes

mi&ht not #e confi&ured- we mi&ht run into trou#le if we stored the elements in a ve*tor #ecause it would #e difficult to determine whether a particular position in the ve*tor was empty or filled with a valid station! 'nstead- we'll implement the &:Iadio usin& a ma$ that maps from the preset num#er to the station at the preset! 'f a particular value #etween 1 and 6 is not a key in the ma$- then the preset has not #een confi&uredQ if it is a key- then its value is the preset! This leads to the followin& version of &:Iadio=
stru*t &:Iadio { double fre[uen*%; int volume; ma$ int, double) $resets; #;

'f ' then wanted to pro&ram my radio as descri#ed a#ove- ' would do so as follows=
&:Iadio m%Iadio; m%Iadio.$resets[8] = FF.H; m%Iadio.$resets[E] = FM.C;

Abusing t.e 2( 4adio The definition of &:Iadio from a#ove seems reasona#ly strai&htforward! 't has three fields that correspond to some attri#ute of the radio! Unfortunately- however- usin& this &:Iadio in any comple) software system can cause pro#lems! The reason is that there are certain restrictions on what values the fields of the &:Iadio can and cannot #e- #ut there is no means of enforcin& those restrictions! 8or e)ample- in the United States- all 8B radio fre5uencies are #etween ED!? and 10E!0 B/z! Conse5uentlythe fre[uen*% field should never #e set to any value out of this ran&e- since doin& so would #e meanin&less! Similarly- we've stated that we don't want the volume field to leave the ran&e 0 to 10- #ut nothin& prevents clients of &:Iadio from doin& so! 8inally- the presets field has to o#ey two restrictions= that the keys are inte&ers #etween 1 and 6- and that the values are doubles restricted to the ran&e of valid fre5uencies! "ow- suppose that someone who does not have this intimate knowled&e of the 8B radio class we've desi&ned comes alon& and writes the followin& code=
&:Iadio m%Iadio; m%Iadio.fre[uen*% = 880.0; "" 1roblem4 (nvalid fre[uen*% m%Iadio.volume = 88; "" 1roblem4 Jolume out of range m%Iadio.$resets[0] = FH.0; "" 1roblem4 Pad $reset inde+, invalid fre[uen*%

,ll of the a#ove operations are ille&al on 8B radios- #ut this code compiles and runs *ust fine! Boreoverthere is no indication at runtime that this code isn't &oin& to work correctly! Jverythin& that the client has done is perfectly le&al C++- and the compiler has no idea that somethin& #ad mi&ht happen in the future! To &ive a conte)t of where thin&s can &o wron&- suppose that we have a function that ad*usts the power level to some system peripheral to tune in to the proper fre5uency! 7ecause all le&al fre5uencies are #etween ED!? and 10E!0 B/z- the code ad*usts the power level to a floatin&1point value such that the power is 0!0 at the lowest possi#le fre5uency KED!? B/zL and 1!0 at the hi&hest fre5uency K10E!0 B/zL! This code is shown #elow- assumin& the e)istence of a 6et9evi*e<o'er function that actually sets the device power=

Chapter H& Abstraction and Classes


void ;uneIe*eiver(&:Iadio radio) { "3 5om$ute the fra*tion of the ma+imum $o'er that this 3 fre[uen*% re[uires. 3" double $o'er7evel = (radio.fre[uen*% - FD.H) " (80F.0 - FD.H); 6et9evi*e<o'er($o'er7evel); #

1 ;0? 1

''ll leave dou#le1checkin& that the a#ove computation &ives the fraction of the power to the transmitter as an e)ercise to the reader! 'n the meantime- think a#out what will happen if we write the followin& code=
&:Iadio m%Iadio; m%Iadio.fre[uen*% = 880.0; m%Iadio.volume = 88; m%Iadio.$resets[0] = FH.0; ;uneIe*eiver(m%Iadio);

0e now have a fairly serious pro#lem on our hands! 7ecause the radio fre5uency is 110!0 B/z- a value out of the valid 8B radio ran&e- the code inside of ;uneIe*eiver is &oin& to set the power level to a nonsensical value! 'n particular- since K110!0 ( ED!?L H K10E!0 ( ED!?L a 1!0<?- the code will turn the receiver on at rou&hly 110b of the ma)imum power it's supposed to receive! 'f we're lucky- the code inside ;uneIe*eiver will have a check that this value is out of ran&e- and the pro&ram will report an error! 'f we're unlucky and the code actually drives too much power into the receiver- we mi&ht overload the device and set it on fire! 'n other words- #ecause the client of the &:Iadio struct set a sin&le field to a nonsensical value- it's possi#le that our pro&ram will crash or cause a physical device malfunction! This is clearly unaccepta#le- and we will need to do somethin& a#out this! (odif/ing t.e 2( 4adio Gf course- that's not all of the pro#lems we mi&ht encounter when workin& with the &:Iadio! Suppose- for e)ample- that we write the followin& function- which sets the radio's fre5uency to the preset at the &iven position if possi#le- and does not chan&e the fre5uency otherwise! The code is as follows=
void 7oad<reset(&:Iadio? radio, int $reset) { "3 5he*B 'hether this $reset e+ists. 3" ma$ int, double)44iterator itr = radio.$resets.find($reset); "3 (f not, donAt do an%thing. 3" if (itr == radio.$resets.end()) return; "3 =ther'ise, *hange the radio fre[uen*%. 3" radio.fre[uen*% = itr-)se*ond; #

"ow- suppose that for some reason Kefficiency- perhapsL that we decide to chan&e the &:Iadio stru*t so that the presets are implemented as an array of dou#les! 0e ar#itrarily say that any preset that has not #een pro&rammed will #e represented #y havin& the value 0 stored in a particular slot! That is- &iven my "CF travel presets- the preset array would look like this= Talue 'nde) EE!? 0 E<!@ 1 0 ; 0 @ 0 A 0 ?

1 ;06 1

Chapter H& Abstraction and Classes

This re5uires us to chan&e the definition of the &:Iadio interface to use a raw array instead of an ST ma$! The updated definition is shown here=
stru*t &:Iadio { double fre[uen*%; int volume; double $resets[N]; #;

0e now have a serious pro#lem! ,lmost of the code that we've written previously that uses the &:Iadio's preset field will fail to compile! 8or e)ample- our earlier code for 7oad<reset will call $resets.findwhich does not e)ist in a raw array! This means that this sin&le chan&e mi&ht re5uire us to rewrite hu&e amounts of code! 'n a small pro*ect- this is a mere annoyance- #ut in a lar&e system on the order of millions of lines of code mi&ht #e so time1consumin& as to render the chan&e impossi#le! 1.at 1ent 1rong: The a#ove discussion hi&hli&hted two pro#lems with the &:Iadio stru*t! 8irst- &:Iadio provides no means for enforcin& its invariants! 7ecause the aspects of the 8B radio were represented in &:Iadio #y raw varia#les- any part of the pro&ram can modify those varia#les without the &:Iadio &ettin& a chance to intervene! 'n other words- the &:Iadio e)pects that certain relations hold #etween its fields- #ut has no mechanism for enforcin& those relations! Second- #ecause the &:Iadio is represented in software as a particular implementation of an 8B radio- code that uses the 8B radio necessarily locks the 8B radio into that particular implementation! Usin& the terminolo&y from the earlier in this chapter- this implementation of the 8B radio provides no abstraction and no encapsulation! The &:Iadio interface is its implementation ( that is- the operations that clients can perform on the &:Iadio are manipulations of the fields that compose the &:Iadio! Chan&in& the implementation thus chan&es the interface- which is why chan&in& the fields #reaks e)istin& code! Similarly- #ecause the interface of &:Iadio is the set of all possi#le manipulations of the data mem#ers- clients can tweak the &:Iadio in any way they see fit- even if such manipulations #reak internal invariants! This is the reality of what C++ pro&rammin& is like without classes! Code #ases are more #rittle- #u&s are more likely- and chan&es are more difficult! ,s we now chan&e &ears and see how to represent an 8B radio usin& classes- keep this startin& point in mind! 7y the time you finish this chapter- the 8B radio will #e si&nificantly more ro#ust than it is now! Introduction to Classes 'n C++- a class is an inter$ace paired with an implementation! ike stru*ts- classes define new types that can #e created and used elsewhere in the pro&ram! 7ecause classes pair an implementation and an interface- the structure of an individual class can #e partitioned into two halves ( the public inter$ace specifyin& how clients interact with the class- and the private implementation- which specifies how functions in the pu#lic interface are implemented! Father than divin& head1first into a full1#lown class definition- we'll investi&ate each of these parts individually! 0e will focus first on how to declare the class- and worry a#out the implementation later! Defining a !ublic Interface et's return to the e)ample of the 8B radio! 0e are interested in desi&nin& an a#straction that represents an 8B radio- then e)pressin& the radio in software! 'n particular- we want our radio to have three pieces of data= the current fre5uency Kin B/zL- the volume Kfrom 0 to 10L- and the presets! ,s we saw in the failed e)periment with stru*t &:Iadio- we cannot simply &ive clients direct access to the fields that ultimately

Chapter H& Abstraction and Classes

1 ;0D 1

implement these properties! /ow- then- can we desi&n an 8B radio that contains some data #ut which does not allow clients to directly modify the data> The answer is a su#tle yet #eautiful trick that is u#i5uitous in modern software! 0e will create a set of functions that set and 5uery the value of these data mem#ers! 0e then prevent the client from directly accessin& the data mem#ers that these functions manipulate! The ma*or advanta&e of this approach is that every operation that could potentially read or modify the data must &o throu&h this small set of functions! Conse5uently- the implementer retains full control over what operations manipulate the class's implementation! "ow- let's see how one mi&ht e)press this in C++! 0e will rewrite our &:Iadio stru*t from earlier to convert it into a fully1fled&ed C++ class! To #e&in- we use the C++ *lass keyword to indicate that we're definin& a new class called &:Iadio! This is shown here=
*lass &:Iadio { #;

Currently- this class is empty and is useless! 0e'll thus start definin& the pu#lic interface #y which clients of &:Iadio will interact with the class! 'n C++- to define a class's pu#lic interface- we use the $ubli* keyword to indicate the start of the interface- and then list the functions contained in that pu#lic interface! This leads us to the followin& code=
*lass &:Iadio { $ubli*4 #;

That is, the p#blic 0eyword, *ollowed by a colon. +ny de*initions that *ollow the p#blic 0eyword will be incl#ded as part o* the class.s p#blic inter*ace. &#t what *#nctions sho#ld we p#t in here: Bet.s be/in by lettin/ the client E#ery and set the radio.s *reE#ency. To do this, we.ll de*ine two member *#nctions called get&re[uen*% and set&re[uen*%. This is shown hereF
*lass &:Iadio { $ubli*4 double get&re[uen*%(); void set&re[uen*%(double ne'&re[); #;

These functions are called mem#er functions of the &:Iadio class! ,lthou&h they look like re&ular function prototypes- #ecause these functions are defined inside of &:Iadio- they are local to that class! 'n fact- callin& the function get&re[uen*% #y itself will result in a compile1time error #ecause there is no &lo#al function called get&re[uen*%! 'nstead- we've defined a function that can #e invoked on an o#*ect of type &:Iadio! To see how this works- let's create a new o#*ect of type &:Iadio! This is syntactically identical to the code for creatin& instances of a stru*t type ( we put the name of the type- followed #y the varia#le name! This is shown here=
&:Iadio m%Iadio; "" 9e*lare a ne' variable of t%$e &:Iadio

"ow that we have this m%Iadio o#*ect- we can ask it for its fre5uency #y invokin& the get&re[uen*% mem#er function! This is shown here=
&:Iadio m%Iadio; double f = m%Iadio.get&re[uen*%(); "" `uer% the radio for its fre[uen*%

"ote that this code will not run as written- #ecause we have not yet implemented the get&re[uen*%() functionQ we'll see how to do that later in this chapter! /owever- this synta) should seem familiar- as it's

1 ;0E 1

Chapter H& Abstraction and Classes

the same synta) we used to invoke functions on ST containers- stream o#*ects- and strin&s! 'n fact- all of those o#*ects are instances of classes! .ou're on the road to learnin& how these comple) o#*ects are put to&etherR et's continue desi&nin& our interface! 0e also want a means for the client to set and read the radio volume! ,lon& the same lines as #efore- we can add a pair of mem#er functions to &:Iadio to &rant access to this data! This is shown here=
*lass &:Iadio { $ubli*4 double get&re[uen*%(); void set&re[uen*%(double ne'&re[); int void #; getJolume(); setJolume(int ne'Jolume);

Clients can then read and write the volume #y writin& code like this=
&:Iadio m%Iadio; m%Iadio.setJolume(F); *out m%Iadio.getJolume() endl;

,&ain- this code will not run #ecause we haven't implemented either of these functions! 2on't worry- we're almost at the point where we'll #e a#le to do this! Bet #s now consider the *inal piece o* the &:Iadio inter*ace G the code *or manip#latin/ presets. Hith the previo#s two properties (vol#me and *reE#ency) we were wor0in/ with a sin/le entity, b#t we now m#st desi/n an inter*ace to let clients read and write m#ltiple di**erent val#es. Ioreover, some o* these val#es mi/ht not e4ist, since the presets mi/ht not yet be pro/rammed in. To desi/n a /ood inter*ace, we sho#ld consider what clients wo#ld li0e to do with presets. He sho#ld certainly allow clients to set each o* the presets. +dditionally, clients sho#ld be able to chec0 whether a certain preset has been pro/rammed in. Jinally, clients sho#ld be able to read bac0 the presets they.ve pro/rammed in, ass#min/ they e4ist. He can represent each o* these operations with a member *#nction, leadin/ to this inter*ace *or the &:Iadio classF
*lass &:Iadio { $ubli*4 double get&re[uen*%(); void set&re[uen*%(double ne'&re[); int void getJolume(); setJolume(int ne'Jolume);

#;

double set<reset(int inde+, double fre[); bool $resetE+ists(int inde+); double get<reset(int inde+);

0e now have an interface for our &:Iadio class! "ow- let's see how we specify the implementation of this interface! 1riting a Class Im+lementation , C++ class represents an a#straction- which consists of an interface into some o#*ect! 0e've *ust seen how to define the interface for the class- and now we must provide an implementation of that interface!

Chapter H& Abstraction and Classes

1 ;0< 1

This implementation consists of two parts! 8irst- we must define what varia#les we will use to implement the class! This is akin to choosin& the fields we put in a stru*t for the information to #e useful! Secondwe must provide an implementation of each of the mem#er functions we defined in the class's pu#lic interface! 0e will do each of these in a separate step! 'f you'll recall- one old version of &:Iadio was a struct that looked like this=
stru*t &:Iadio { double fre[uen*%; int volume; ma$ int, double) $resets; #;

This is a perfectly fine implementation of an &:Iadio since it allows us to store all of the information we could possi#ly need! 0e'll therefore modify our implementation of the &:Iadio class so that it is implemented usin& these three fields! /owever- we want to do this in a way that prevents clients of &:Iadio from accessin& the fields directly! 8or this purpose- C++ provides the $rivate keyword- which indicates that certain parts of a class are completely off1limits to clients! This is shown here=
*lass &:Iadio { $ubli*4 double get&re[uen*%(); void set&re[uen*%(double ne'&re[); int void getJolume(); setJolume(int ne'Jolume);

double set<reset(int inde+, double fre[); bool $resetE+ists(int inde+); double get<reset(int inde+); $rivate4 double fre[uen*%; int volume; ma$ int, double) $resets; #;

0hen referrin& to elements of a stru*t- one typically uses the term $ield! 'n the conte)t of classes- these varia#les are called data members! That is- fre[uen*% is a data member of &:Iadio- and getJolume is a member $unction! 7ecause we've marked these data mem#ers private- the C++ compiler will enforce that no client of the &:Iadio class can access them! 8or e)ample- consider the followin& code=
&:Iadio m%Iadio; m%Iadio.fre[uen*% = 880.0; "" 1roblem4 (llegal; fre[uen*% is $rivate

This code will cause a compile1time error #ecause the fre5uency data mem#er is private! To write code to this effect- clients would have to use the pu#lic interface- in particular the set&re[uen*% mem#er function- as shown here=
&:Iadio m%Iadio; m%Iadio.set&re[uen*%(880.0); "" 7egal4 set&re[uen*% is $ubli*

1 ;10 1

Chapter H& Abstraction and Classes

,ll that's left to do now is implement the mem#er functions on the &:Iadio class! 'mplementin& a mem#er function is syntactically similar to implementin& a re&ular function- thou&h there are a few differences! Gne o#vious syntactic difference is the means #y which we specify the name of the function! 'f we are interested in implementin& the get&re[uen*% function of &:Iadio- for e)ample- then we would #e&in as follows=
double &:Iadio44get&re[uen*%() { "3 ... im$lementation goes here ... 3" #

"otice that the name of the function is &:Iadio44get&re[uen*%! The dou#le1colon operator K44L is called the scope resolution operator and tells C++ where to look for the function we want to implement! .ou can think of the synta) R44S as meanin& 4look inside R for S!6 0hen implementin& mem#er functionsit is e)tremely important that you make sure to use the full name of the function you want to implement! 'f instead we had written the followin&=
double get&re[uen*%() { "" 1roblem4 7egal but in*orre*t "3 ... im$lementation goes here ... 3" #

Then C++ would think that we were implementin& a re&ular function called get&re[uen*% that has no relationship whatsoever to the get&re[uen*% function inside of &:Iadio! "ow that we've seen how to tell C++ that we're implementin& the function- what code should we write inside of the function> 0e know that the function should return the 8B radio's current fre5uency! Boreover- the fre5uency is stored inside of a data mem#er called fre[uen*%! Conse5uently- we can write the followin& code for &:Iadio44get&re[uen*%=
double &:Iadio44get&re[uen*%() { return fre[uen*%; #

This may look a #it confusin&- so let's take a second to think a#out what's &oin& on here! This function is a sin&le line- return fre[uen*%! 'f you'll notice- nowhere in the get&re[uen*%() function did we define a varia#le called fre[uen*%- #ut this function still compiles and runs correctly! The reason is as follows ( inside of a mem#er function- all of the class's data mem#ers can #e accessed #y name! That is- when implementin& the get&re[uen*% function- we can freely access and manipulate any or all of the class's data mem#ers #y referrin& to them #y name! 0e don't need to indicate that fre[uen*% is a data mem#ernor do we have to specify which &:Iadio's fre[uen*% data mem#er we're referrin& to! 7y default- C++ assumes that all data mem#ers are the data mem#ers of the receiver o#*ect- and so the line return fre5uency means 4return the value of the fre[uen*% data mem#er of the o#*ect on which this function was invoked!6 ,t this point- let us more formally define what the pu#lic and private access specifiers actually mean! 'f a mem#er of a class is marked pu#lic- then any part of the code can access and manipulate it! Thus if you have a pu#lic mem#er function in the class interface- all code can access it! 'f a class mem#er is marked private- then the only pieces of the code that can access that mem#er are the mem#er functions of the class! That is- private data can only #e read and written #y the implementations of the class's mem#er functions! 'n this sense- the pu#lic and private keywords are C++'s mechanism for definin& interfaces and enforcin& encapsulation! , class's interface is defined #y all of its pu#lic mem#ers- and its implementation #y the implementations of those pu#lic mem#er functions alon& with any private data mem#ers! The compiler enforces encapsulation #y disallowin& class clients from directly accessin& private data- and so

Chapter H& Abstraction and Classes

1 ;11 1

the implementation can assume that any access to the class's private data &oes throu&h the pu#lic interface! et's conclude this section #y implementin& the remainin& pieces of the &:Iadio class! 8irst- let's implement the set&re[uen*% function- which sets the radio's fre5uency to a particular value! 'f you'll recall- all 8B radio fre5uencies must #e #etween ED!? B/z and 10E!0 B/z! Thus- we'll have this function verify that the new fre5uency is in this ran&e- and will then set the fre5uency to #e in that ran&e if so! /ere's one possi#le implementation=
void &:Iadio44set&re[uen*%(double ne'&re[) { assert(ne'&re[ )= FD.H ?? ne'&re[ = 80F.0); fre[uen*% = ne'&re[; #

/ere- the assert function- defined in *assert)- is a function that tests whether the particular condition is true and a#orts the pro&ram with a useful error messa&e if it isn't! assert is useful in testin& #ecause it allows you to verify that certain invariants hold in your pro&rams in a means conducive to de#u&&in&! Clus- most compilers completely remove assert statements from release #uilds- so there's no runtime overhead when you decide to ship your software! This is a remarka#ly simple two lines of code! 0e first assert that the fre5uency is in ran&e- and then set the fre5uency data mem#er of the class to the new value! 0hat's so fantastic a#out this code is that it allows us to enforce the restriction that the fre5uency #e constrained to the ran&e spanned #y ED!? B/z to 10E!0 B/z! 7ecause the only way that clients can chan&e the fre5uency data mem#er is throu&h the set8re5uency function- we can prevent the fre5uency from ever #ein& set to a value out of ran&e! 0e'll discuss this in more detail when we talk a#out class invariants! Usin& the implementation of the getHset&re[uen*% functions as a #asis- we can easily implement the getHsetJolume functions! This is shown here=
int &:Iadio44getJolume() { return volume; # void &:Iadio44setJolume(int ne'Jol) { assert(ne'Jol )= 0 ?? ne'Jol = 80); volume = ne'Jol; #

This pattern of pairin& a get3 function alon& with a set3 function is e)tremely common- and you will undou#tedly see it in any ma*or C++ pro*ect you work on! 0e'll detail e)actly why it is such a useful desi&n later in this chapter! The final three functions we wish to implement are the set<reset- $resetE+ists- and get<reset functions! These functions are in some ways similar to the getHsetJolume functions- #ut differ in that the values they read and write mi&ht not e)ist! 0e'll #e&in with set<reset- which is shown here=
void &:Iadio44set<reset(int inde+, double fre[) { assert(inde+ )= 8 ?? inde+ = N); assert(fre[ )= FD.H ?? fre[ = 80F.0); $resets[inde+] = fre[; #

1 ;1; 1

Chapter H& Abstraction and Classes

The $resetE+ists function can #e implemented 5uite simply #y returnin& whether the ma$ contains the specified key! /owever- there's one detail we didn't consider ( what happens if the inde) is out of #ounds> That is- what do we do if the client asks whether preset 0 e)ists- or whether preset 1@D e)ists> 0e could implement $resetE+ists to so that it returns false in these cases Ksince there are no presets in those slotsL- #ut it seems more reasona#le to have the function assert that the value is in #ounds first! The reason is that if a client is 5ueryin& whether a preset that is out of the desired ran&e e)ists- it almost certainly represents a lo&ical error! Usin& assert to check that the value is in #ounds will let us de#u& the pro&ram more easily! This leads to the followin& implementation of $resetE+ists=
bool &:Iadio44$resetE+ists(int inde+) { assert(inde+ )= 8 ?? inde+ = N); return $resets.find(inde+) 1= $resets.end(); #

8inally- we'll implement the get<reset function! Since there is no meanin&ful value to return if the preset doesn't e)ist- we'll have this function verify that the preset is indeed valid #efore returnin& it! This is shown here=
double &:Iadio44get<reset(int inde+) { assert($resetE+ists(inde+)); return $resets[inde+]; #

"otice that in this function- we invoked the $resetE+ists mem#er function! ,s with private data mem#ers- C++ lets you call mem#er functions of the receiver o#*ect without havin& to e)plicitly specify which o#*ect you are referrin& to! That is- the compiler is smart enou&h to tell that the call to $resetE+ists(inde+) should #e interpreted as 4call the $resetE+ists function on the receiver o#*ectpassin& in the value inde+!6 This also #rin&s up another important point= it is perfectly le&al to use a class's pu#lic interface in its implementation! 'n fact- doin& so is often a wise idea! 'f we had implemented get<reset without callin& $resetE+ists- we would have to duplicate a reasona#le amount of codewhich is in &eneral a very #ad idea! Com+aring classes and structs Jarlier in this chapter- we saw how representin& the &:Iadio as a stru*t led to all sorts of pro#lems! The stru*t had no means of enforcin& invariants- and any chan&e to the stru*t's fields could #reak a potentially un#ounded amount of code! 0e discussed earlier at a hi&h level how a#straction and encapsulation can prevent these pro#lems from occurrin&! 2oes the class mechanism- which is desi&ned to represent these ideas in software- prevent the aforementioned pro#lems from happenin&> et's take a few minutes to see whether this is the case! Classes )nforce In;ariants ,n invariant is a property of a set of data that always holds true for that data! 8or e)ample- one possi#le invariant mi&ht #e that a certain value always #e even- while another could #e that the difference #etween two values is less than fourteen! 'n our e)ample with &:Iadio- our class had several invariants= The radio's fre5uency is always #etween ED!? B/z and 10E!E B/z! The radio's volume is a value #etween 0 and 10- inclusive! The radio's presets are num#ered #etween 1 and 6- and are valid fre5uencies!

The stru*t version of &:Iadio failed to enforce any of these invariants #ecause clients could &o in and directly modify the fields responsi#le for holdin& the data! 'n the class version- however- any access to the

Chapter H& Abstraction and Classes

1 ;1@ 1

data mem#ers that represent these 5uantities must &o throu&h the appropriate set3 and get3 functions! This allows the implementation to dou#le1check that all of the invariants hold #efore modifyin& the class's data mem#ers! 8or e)ample- let's review the implementation of set<reset=
void &:Iadio44set<reset(int inde+, double fre[) { assert(inde+ )= 8 ?? inde+ = N); assert(fre[ )= FD.H ?? fre[ = 80F.0); $resets[inde+] = fre[; #

This is the only function in the interface that allows clients to modify the radio's presets! 7efore the function writes a value to one of the presets- it verifies that the inde) and fre5uency are in ran&e! Conse5uently- if the data mem#er is written to- it is only after the implementer has had a chance to inspect the value and confirm that it is indeed in ran&e! 'n other words- #y restrictin& access to the data mem#ers and instead providin& a set of functions that modify the data mem#ers- the implementer can prevent clients from modifyin& the implementation in a way that violates the class invariants! Classes )nforce )nca+sulation Fecall that when we implemented the &:Iadio as a stru*t- chan&in& any of the fields would #reak e)istin& code! The reason for this is that any manipulations of the stru*t re5uired direct access to the fields of the stru*t! 0hen usin& classes- however- all operations on the class must &o throu&h an additional layer ( the interface ( which is independent of the current implementation! 8or e)ampleconsider the followin& code=
&:Iadio m%Iadio; m%Iadio.setJolume(80); *out m%Iadio.getJolume() endl;

This isn't the most e)citin& code we've written- #ut it illustrates how a client mi&ht read and set the radio's volume! "ow- suppose that we are implementin& the &:Iadio class so that it interacts with a real set of speakers! 'nitially- you mi&ht think that the speaker volume is controlled #y modifyin& how much power the speakers receiveQ at lower power- the speakers output less sound! 'n reality- thou&h- most speaker volumes are controlled #y modifyin& how much attenuation the sound si&nal receives! That is- when a speaker is at full volume- the attenuation level is zero- and the speaker plays the sound at ma)imum volume! 0hen the volume is zero Kthe sound is mutedL- the attenuation level is 100b and the speakers produce no sound! 'n other words- the volume control is represented #y determinin& how much attenuation to insert! Conse5uently- whenever we want to increase the volume- we would decrease the attenuation- and vice1versa! 3iven this description- we therefore mi&ht chan&e the implementation of the &:Iadio class so that the volume is represented internally as an attenuation amount! /ere's the modified class=
*lass &:Iadio { $ubli*4 double get&re[uen*%(); void set&re[uen*%(double ne'&re[); int void getJolume(); setJolume(int ne'Jolume);

double set<reset(int inde+, double fre[); bool $resetE+ists(int inde+); double get<reset(int inde+);

1 ;1A 1

Chapter H& Abstraction and Classes

$rivate4 double fre[uen*%; int attenuation; "" 0 is no attenuation, 80 is ma+imum attenuation ma$ int, double) $resets; #;

&eca#se we.ve chan/ed the internal representation o* the &:Iadio, we will need to chan/e the implementation o* the get'setJolume *#nctions. -ow, these *#nctions are desi/ned so that the #ser inp#ts an amo#nt o* vol#me, not an amo#nt o* atten#ation, and so the *#nctions will have to do a E#ic0 behind)the)scenes calc#lation to convert between the two. Here.s one possible implementation o* setJolumeF
void &:Iadio44setJolume(int ne'Jol) { assert(ne'Jol )= 0 ?? ne'Jol = 80); "" @n*hanged attenuation = 80 - ne'Jol; "" 5onvert from volume to attenuation level #

/ere- the code for setJolume takes in a volume level from the client- then converts it into an attenuation level #y su#tractin& the volume from ten! This means that volume 10 corresponds to 0 attenuation- volume D to @ attenuation- etc! "ow- how mi&ht we &o a#out chan&in& the implementation of getJolume> This function must return a volume #etween 0 and 10 with 0 meanin& no volume and 10 meanin& ma)imum volume- #ut we've implemented the volume level internally as the attenuation! This means that the function must do a 5uick calculation to convert #etween the two! The resultin& implementation is shown here=
int &:Iadio44getJolume() { return 80 - attenuation; #

''ll leave it as an e)ercise to the reader to verify that this computation is correct! 8 'n this short discussion- we completely chan&ed the internal implementation of the radio volume! 7ut from a client's perspective- a#solutely nothin& has chan&ed! Fecall the client code we wrote earlier on for chan&in& the radio volume=
&:Iadio m%Iadio; m%Iadio.setJolume(80); *out m%Iadio.getJolume() endl;

This code is still perfectly le&al- and moreover it produces the e)act same output as #efore! 7ecause this code only uses the class's pu#lic interface- the client cannot tell that callin& m%Iadio.setJolume(80) actually sets an internal field in the &:Iadio to zero- nor can she tell that callin& m%Iadio.getJolume() will perform a conversion #ehind1the1scenes! 'n other words- usin& the pu#lic interface allows clients of &:Iadio to write code that will compile and run correctly even if the entire implementation of the &:Iadio has chan&ed! Class Constructors Gne of the recurrin& themes of this chapter has #een that classes can enforce invariants! /owever- usin& only the techni5ues we've covered so far- there are some invariants that classes cannot enforce automatically! To see this- let's return to the &:Iadio class! 'f you'll recall- when implementin& &:Iadio usin& a stru*t- we saw that one possi#le implementation of the preset list was to use an array of si)

Chapter H& Abstraction and Classes

1 ;1? 1

doubles- where an unpro&rammed preset has value 0!0! et's modify our ori&inal implementation of the &:Iadio class so that we use this implementation strate&y! The new class looks like this=

1 ;16 1
*lass &:Iadio { $ubli*4 double get&re[uen*%(); void set&re[uen*%(double ne'&re[); int void getJolume(); setJolume(int ne'Jolume);

Chapter H& Abstraction and Classes

double set<reset(int inde+, double fre[); bool $resetE+ists(int inde+); double get<reset(int inde+); $rivate4 double fre[uen*%; int volume; double $resets[N]; #;

This- of course- necessitates that we chan&e our implementation of $resetE+ists- since we no lon&er represent the preset list as a map! The new implementation is shown here=
bool &:Iadio44$resetE+ists(int inde+) { assert(inde+ )= 8 ?? inde+ = N); return $resets[inde+ - 8] == 0.0; "" -8 ma$s [8, N] to [0, H] #

3iven this implementation- what is the result of runnin& the followin& code snippet>
&:Iadio m%Iadio; if (m%Iadio.$resetE+ists(8)) *out /<reset 84 / m%Iadio.get<reset(8) else *out /<reset 8 not $rogrammed./ endl;

endl;

'ntuitively- this pro&ram should print out that preset one is not pro&rammed- since we *ust created the radio! Unfortunately- thou&h- this pro&ram produces undefined #ehavior! /ere is the output from several different runs of the pro&ram on my machine=
1reset 1reset 1reset 1reset 1" 3.(0)eD10, 1 not programmed. 1" -1.0++e-3) 1" ).33)eD(0

This certainly doesn't seem ri&htR 0hat's &oin& on here> The pro#lem is that all of the data mem#ers of &:Iadio are primitive types- and unless you e)plicitly initialize a primitive type- it will hold whatever value happens to #e in memory at the time that it is created! 'n particular- this means that the presets array will #e filled with &ar#a&e- and so the $resetE+ists and get<reset functions will #e workin& with &ar#a&e data! 3ar#a&e data is never a &ood thin&- #ut it is even more pro#lematic from the standpoint of class invariants! The &:Iadio assumes that certain constraints hold for its data mem#ers- #ut those data mem#ers are initialized randomly! /ow can &:Iadio ensure that it #ehaves consistently when it does not have control over its implementation> The answer is simple= it can't- and we're &oin& to need to refine our approach to make everythin& work correctly!

Chapter H& Abstraction and Classes A 6te+ in t.e 4ig.t Direction8 init34

1 ;1D 1

Gne way that we could fi) this pro#lem is to create a new mem#er function called init that initializes all of the data mem#ers! 0e then re5uire all clients of the &:Iadio class to call this init function #efore usin& the other mem#er functions of the &:Iadio class! ,ssumin& that clients ensure to call init #efore usin& the &:Iadio- this should solve all of our pro#lems! et's take a minute to see how we mi&ht implement the init function! 8irst- we need to modify the class's pu#lic interface- as shown here=
*lass &:Iadio { $ubli*4 void init(); double get&re[uen*%(); void set&re[uen*%(double ne'&re[); int void getJolume(); setJolume(int ne'Jolume);

double set<reset(int inde+, double fre[); bool $resetE+ists(int inde+); double get<reset(int inde+); $rivate4 double fre[uen*%; int volume; double $resets[N]; #;

0e could then implement init as follows=


void &:Iadio44init() { for(siUeLt i = 0; i N; !!i) $resets[i] = 0.0; #

This is certainly a step in the ri/ht direction. He no lon/er have to worry abo#t the presets array containin/ #ninitiali=ed val#es. &#t what o* the other data members, *reE#ency and vol#me: They too m#st be initiali=ed to some meanin/*#l val#e. He can there*ore #pdate the init *#nction to set them to some reasonable val#e. Jor simplicity, let.s set the *reE#ency to 6$. IH= (the minim#m possible *reE#ency) and set the vol#me to *ive. This is shown hereF
void &:Iadio44init() { for(siUeLt i = 0; i N; !!i) $resets[i] = 0.0; fre[uen*% = FD.H; volume = H; #

't may seem stran&e that we have to initialize fre5uency and volume inside of the init function! ,fter allwhy can't we do somethin& like this>

1 ;1E 1
*lass &:Iadio { $ubli*4 void init(); double get&re[uen*%(); void set&re[uen*%(double ne'&re[); int void getJolume(); setJolume(int ne'Jolume);

Chapter H& Abstraction and Classes

double set<reset(int inde+, double fre[); bool $resetE+ists(int inde+); double get<reset(int inde+); $rivate4 double fre[uen*% = FD.H; int volume = H; double $resets[N]; #; "" 1roblem4 Kot legal 5!! "" 1roblem4 Kot legal 5!!

Unfortunately- this is not le&al C++ code! There isn't a particularly &ood reason why this is the case- and in the ne)t release of C++ this synta) will #e supported- #ut for now we have to manually initialize everythin& in the init function! 1./ init34 is Insufficient The approach we've outlined a#ove seems to solve all of our pro#lems! Jvery time that we create an &:Iadio- we manually invoke the init function! This solves our pro#lem- #ut puts an e)tra #urden on the client! 'n particular- if a client does not call the init function- our o#*ect's internals will not #e confi&ured properly and any use of the o#*ect will almost certainly cause some sort of runtime error! The pro#lem with init is that it does not make lo&ical sense! 0hen you purchase a physical o#*ect- most of the time- that o#*ect is fully assem#led and ready to &o! 0hen you #uy a stapler- you don't #uy the component parts and then assem#le itQ you #uy a finished product! .ou don't purchase a car and then manually connect the transmission to the rest of the en&ineQ you assume that the car manufacturer has done this for you! 'n other words- #y the time that you #e&in usin& an o#*ect- you e)pect it to #e assem#led! 8rom the standpoint of physical o#*ects- this is #ecause you are #uyin& a lo&ically complete o#*ect- not a collection of components! 8rom the standpoint of a#straction- this is #ecause it #reaches the wall of a#straction if you are re5uired to set up an o#*ect into a well1formed state #efore you #e&in usin& it! "one of the o#*ects we've seen so far have re5uired any function like init! The ST ve*tor and ma$ are initialized to sensi#le defaults #efore you #e&in usin& them- and strings default to holdin& the empty strin& without any e)plicit intervention #y the user! 7ut how do they do this> 't's throu&h the ma&ic of a special mem#er function called the constructor! Class Constructors , constructor is a special mem#er function whose *o# is to initialize the o#*ect into a well1formed state #efore clients start manipulatin& that o#*ect! 'n this sense- constructors are like the init function we wrote earlier! /owever- constructors have the special property that they are called automatically whenever an o#*ect is constructed! That is- if you have a class that defines a constructor- that constructor is &uaranteed to e)ecute whenever you create an o#*ect of the class type! Syntactically- a constructor is a mem#er function whose name is the same as the name of the class! 8or e)ample- the strin& constructor is a function named strin&==strin&- and in our &:Iadio e)ample- the

Chapter H& Abstraction and Classes

1 ;1< 1

constructor is a mem#er function named &:Iadio44&:Iadio! /ere is a refined interface for &:Iadio that includes a class constructor=
*lass &:Iadio { $ubli*4 &:Iadio(); double get&re[uen*%(); void set&re[uen*%(double ne'&re[); int void getJolume(); setJolume(int ne'Jolume);

double set<reset(int inde+, double fre[); bool $resetE+ists(int inde+); double get<reset(int inde+); $rivate4 double fre[uen*%; int volume; double $resets[N]; #;

"otice that the constructor has no return type- not even void! This may seem stran&e at first- #ut will make su#stantially more sense once you see how and where the constructor is invoked! Syntactically- one implements a constructor *ust as one would any other mem#er function! The only difference is that the constructor does not have a return type- and so the synta) for implementin& a constructor looks like this=
&:Iadio44&:Iadio() { "3 ... im$lementation goes here ... 3" #

Constructors are like any other function- and so we can put whatever code we feel like in the #ody of the constructor! /owever- the constructor should ensure that all of the o#*ect's data mem#ers that need manually initialization are manually initialized! 'n our case- this means that we mi&ht implement the &:Iadio constructor as follows=
&:Iadio44&:Iadio() { for(siUeLt i = 0; i N; !!i) $resets[i] = 0.0; fre[uen*% = FD.H; volume = H; #

-ow, whenever we create an instance o* the &:Iadio type, the obAect will be set #p correctly. That is, when we write code li0e thisF
&:Iadio m%Iadio; if (m%Iadio.$resetE+ists(8)) *out a<reset 84 a m%Iadio.get<reset(8) else *out a<reset 8 not $rogrammed.b endl;

endl;

1 ;;0 1

Chapter H& Abstraction and Classes

The output will always #e 4Creset 1 not pro&rammed!6 This is #ecause in the line where we create the m%Iadio o#*ect- C++ automatically invokes the constructor- which zeros out all of the presets! 't is ille&al to call a class's constructorQ C++ will always do this for you! 8or e)ample- the followin& code will not compile=
&:Iadio m%Iadio; m%Iadio.&:Iadio(); "" 1roblem4 5annot manuall% invoBe *onstru*tor

This may seem like an unusual restriction- #ut is actually 5uite useful! 7ecause the constructor is invoked when and only when the class is #ein& constructed for the first time- you don't need to worry a#out unusual conditions where the class is #ein& instantiated #ut meanin&ful data is already stored in the class! ,dditionally- this makes the role of the constructor e)plicitly clear ( its *o# is to initialize the class to a meanin&ful state- nothin& more! Second- as a conse5uence- constructors can never return values! The constructor is invoked automatically- not &ivin& you a chance to store a returned value even if one were to e)ist! Arguments to Constructors 'n the a#ove e)ample- our &:Iadio constructor takes in no parameters! /owever- it is possi#le to create constructors that take in ar&uments that mi&ht #e necessary for initialization! 8or e)ample- our &:Iadio constructor ar#itrarily sets the fre5uency to ED!? B/z and the volume to ? #ecause we need these values to #e in certain ran&es! There's no particular reason why we should initialize these values this way- #ut in the a#sence of information a#out what the client wants to do with the o#*ect we cannot do any #etter! 7ut what if the client could tell us what she wanted the fre5uency and volume to #e> 'n that case- we could initialize the fre5uency and volume to the user's values- in essence creatin& a radio whose fre5uency and volume were already set up for the user! To do this- we can create a second &:Iadio constructor that takes in a fre5uency and volume- then initializes the radio to those settin&s! Syntactically- a constructor of this sort is a mem#er function named &:Iadio that takes in two parameters! This is shown here=
*lass &:Iadio { $ubli*4 &:Iadio(); &:Iadio(double fre[, int vol); double get&re[uen*%(); void set&re[uen*%(double ne'&re[); int void getJolume(); setJolume(int ne'Jolume);

double set<reset(int inde+, double fre[); bool $resetE+ists(int inde+); double get<reset(int inde+); $rivate4 double fre[uen*%; int volume; double $resets[N]; #;

0e could then implement this function as follows=

Chapter H& Abstraction and Classes

1 ;;1 1

1 ;;; 1
&:Iadio44&:Iadio(double fre[, int vol) { for(siUeLt i = 0; i N; !!i) $resets[i] = 0.0; fre[uen*% = fre[; volume = vol; #

Chapter H& Abstraction and Classes

"ow that we have this constructor- how do we call it> That is- how do we create an o#*ect that is initialized usin& this constructor> The synta) for this is reasona#ly strai&htforward and looks like this=
&:Iadio m%Iadio(FF.H, H);

That is- we write out the type of the o#*ect to create- the name of the o#*ect to create- and then a parenthesized list of the ar&uments to pass into the constructor! .ou may #e wonderin& why in the case of a zero1ar&ument constructor- we do not need to e)plicitly spell out that we want to use the default constructor! 'n other words- why don't we write out code like this=
&:Iadio m%Iadio(); "" 1roblem4 7egal but in*orre*t

This code is perfectly le&al- #ut it does not do what you'd e)pect! There is an unfortunate defect in C++ that causes this statement to #e interpreted as a function prototype rather than the creation of an o#*ect usin& the default constructor! 'n fact- C++ will interpret this as 4prototype a function called m%Iadio that takes in no ar&uments and returns an &:Iadio6 rather than 4create an &:Iadio called m%Iadio usin& the zero1 ar&ument constructor!6 This is sometimes referred to as 4C++'s most ve)in& parse6 and causes e)tremely difficult to understand warnin&s and error messa&es! Thus- if you want to invoke the default constructoromit the parentheses! 'f you want to invoke a parametrized constructor- parenthesize the ar&uments! ,nother important point to remem#er when workin& with multiple constructors is that constructors cannot invoke one another! This is an e)tension of the rule that you cannot directly call a constructor! 'f you need to do the same work in multiple constructors- you can either duplicate the code KyuckRL or use a private mem#er function- which we'll discuss later! Classes 1it.out a @ullar/ Constructor , function is called nullary if it takes no ar&uments! 8or e)ample- the first &:Iadio constructor we wrote is a nullary constructor- since it takes no ar&uments! 'f you define a class and do not provide a constructorC++ will automatically provide you a default nullary constructor that does a#solutely nothin&! This is why in the case of &:Iadio- we needed to provide a nullary constructor to initialize the data mem#ersQ otherwise they would initialize to ar#itrary values! /owever- if you define a class and provide any constructors- C++ will not automatically &enerate a nullary constructor for you! This means that it is possi#le to construct classes that do not have a zero1ar&ument constructor! 8or e)ample- suppose that we remove the nullary constructor from &:IadioQ this results in the followin& class definition=

Chapter H& Abstraction and Classes


*lass &:Iadio { $ubli*4 &:Iadio(double fre[, int vol); double get&re[uen*%(); void set&re[uen*%(double ne'&re[); int void getJolume(); setJolume(int ne'Jolume);

1 ;;@ 1

double set<reset(int inde+, double fre[); bool $resetE+ists(int inde+); double get<reset(int inde+); $rivate4 double fre[uen*%; int volume; double $resets[N]; #;

7ecause this class does not have a nullary constructor- we cannot construct instances of it without passin& in values for the fre5uency and volume! That is- the followin& code is ille&al=
&:Iadio m%Iadio; "" 1roblem4 Ko default *onstru*tor available

,t first- this may seem like a nuisance! /owever- this aspect of class desi&n is e)tremely valua#le #ecause it allows you to create types that must #e initialized to a meanin&ful value! 8or e)ample- suppose that you are desi&nin& a class that represents a ro#ot1controlled laser- either for automated weldin& or delicate sur&ical procedures! 0hen #uildin& such a laser- it is imperative that the laser know how much power to deliver and what points the #eam should #e directed at! These values a#solutely must #e initialized to meanin&ful data- or the laser mi&ht deliver me&awatts of power at a patient or aim at random points firin& the #eam! 'f you wanted to represent the laser as a C++ class- you could force clients to specify this data #efore usin& the laser #y makin& a Iobot7aser class whose only constructor takes in #oth the laser power and laser coordinates! This means that clients could not create instances of Iobot7aser without enterin& coordinates- reducin& the possi#ility of a catastrophic failure! !ri;ate (ember 2unctions et's return once a&ain to our &:Iadio e)ample- this time lookin& at the implementation of three functions= set&re[uen*%- set<reset- and $resetE+ists! The implementations of these functions are shown here=
void &:Iadio44set&re[uen*%(double ne'&re[) { assert(ne'&re[ )= FD.H ?? ne'&re[ = 80F.0); fre[uen*% = ne'&re[; # void &:Iadio44set<reset(int inde+, double fre[) { assert(inde+ )= 8 ?? inde+ = N); assert(fre[ )= FD.H ?? fre[ = 80F.0); $resets[inde+ - 8] = fre[; # double &:Iadio44$resetE+ists(int inde+) { assert(inde+ )= 8 ?? inde+ = N); return $resets[inde+ - 8] == 0.0; #

1 ;;A 1

Chapter H& Abstraction and Classes

"otice that each hi&hli&hted line of code appears in two of the three functions! "ormally this isn't too serious a concern- #ut in this particular case makes the implementation #rittle and fra&ile! 'n particular- if we ever want to chan&e the num#er of presets or the ma)imum fre5uency ran&e- we'll need to modify multiple parts of the code accordin&ly or risk inconsistent handlin& of presets and fre5uencies! To unify the code- we mi&ht consider decomposin& this lo&ic into helper functions! /owever- since the code we're decomposin& out is an implementation detail of the &:Iadio class- class clients shouldn't have access to these helper functions! 'n other words- we want to create a set of functions that simplify class implementation #ut which can't #e accessed #y class clients! 8or situations like these- we can use a techni5ue called private mem#er functions! (arking 2unctions pri#ate 'f you'll recall from earlier- the $rivate keyword indicates which parts of a class cannot #e accessed #y clients! So far we have restricted ourselves to dealin& only with private data mem#ers- #ut it is possi#le to create mem#er functions that are marked private! ike re&ular mem#er functions- these functions can read and write private class data- and are invoked relative to a receiver o#*ect! Unlike pu#lic mem#er functionsthou&h- they can only #e invoked #y the class implementation! Therefore- private mem#er functions are not part of the class's interface and e)ist solely to simplify the class implementation! 2eclarin& a private mem#er function is similar to declarin& a pu#lic mem#er function 1 we *ust add the definition to the class's private data! 'n our &:Iadio e)ample- we will introduce two helper functions= *he*B&re[uen*%- which asserts that a fre5uency is in the proper ran&e- and *he*B<reset- which ensures that a preset inde) is in #ounds! The updated class definition for &:Iadio is shown here=
*lass &:Iadio { $ubli*4 &:Iadio(); &:Iadio(double fre[, int vol); double get&re[uen*%(); void set&re[uen*%(double ne'&re[); int void getJolume(); setJolume(int ne'Jolume);

double set<reset(int inde+, double fre[); bool $resetE+ists(int inde+); double get<reset(int inde+); $rivate4 void void *he*B&re[uen*%(double fre[); *he*B<reset(int inde+);

double fre[uen*%; int volume; double $resets[N]; #;

0e can then implement these functions as follows=

Chapter H& Abstraction and Classes


void &:Iadio44*he*B&re[uen*%(double fre[) { assert(fre[ )= FD.H ?? fre[ = 80F.F); # void &:Iadio44*he*B<reset(int inde+) { assert(inde+ )= 8 ?? inde+ = N); #

1 ;;? 1

Usin& these functions yields the followin& implementations of the three aforementioned functions=
void &:Iadio44set&re[uen*%(double ne'&re[) { *he*B&re[uen*%(ne'&re[); fre[uen*% = ne'&re[; # void &:Iadio44set<reset(int inde+, double fre[) { *he*B<reset(inde+); *he*B&re[uen*%(fre[); $resets[inde+ - 8] = fre[; # bool &:Iadio44$resetE+ists(int inde+) { *he*B<reset(inde+); return $resets[inde+ - 8] == 0.0; #

These functions are si&nificantly cleaner than #efore- and the class as a whole is much more ro#ust to chan&e! 6im+lif/ing Constructors wit. !ri;ate 2unctions Crivate functions can &reatly reduce the implementation comple)ity of classes with multiple constructors! Fecall that our &:Iadio class has two constructors- one which initializes the &:Iadio to have a reasona#le default fre5uency and volume- and one which lets class clients specify the initial fre5uency and volume! The implementation of these two functions is shown here=
&:Iadio44&:Iadio() { for(siUeLt i = 0; i N; !!i) $resets[i] = 0.0; fre[uen*% = FD.H; volume = H; # &:Iadio44&:Iadio(double fre[, int vol) { for(siUeLt i = 0; i N; !!i) $resets[i] = 0.0; fre[uen*% = fre[; volume = vol; #

These functions are e)tremely similar in structure- #ut #ecause C++ does not allow you to manually call a class's constructor! /ow- then- can the two functions #e unified> Simple ( we introduce a private mem#er function which does the initialization- then have the two constructors invoke this mem#er function with the proper ar&uments! This is illustrated #elow=

1 ;;6 1
*lass &:Iadio { $ubli*4 &:Iadio(); &:Iadio(double fre[, int vol); double get&re[uen*%(); void set&re[uen*%(double ne'&re[); int void getJolume(); setJolume(int ne'Jolume);

Chapter H& Abstraction and Classes

double set<reset(int inde+, double fre[); bool $resetE+ists(int inde+); double get<reset(int inde+); $rivate4 void void void *he*B&re[uen*%(double fre[); *he*B<reset(int inde+); initialiUe(double fre[, int vol);

#;

double fre[uen*%; int volume; double $resets[N];

void &:Iadio44initialiUe(double fre[, int vol) { for(siUeLt i = 0; i N; !!i) $resets[i] = 0.0; fre[uen*% = fre[; volume = vol; # &:Iadio44&:Iadio() { initialiUe(FD.H, H); # &:Iadio44&:Iadio(double fre[, int vol) { initialiUe(fre[, vol); #

,s you can see- private mem#er functions are e)tremely useful tools! 0e will continue to use them throu&hout the remainder of this #ook- *ust as you will undou#tedly use them in the course of your pro&rammin& career! !artitioning Classes Across 2iles Gne of the motivations #ehind classes was to provide a means for separatin& out implementation and interface! 0e have seen this already throu&h the use of the $ubli* and $rivate access specifiers- which prevent clients from lookin& at implementation1specific details! /owever- there is another common means #y which implementation is separated from interface- and that is the split #etween header $iles and implementation $iles! ,s you've seen #efore- almost all of the pro&rams you've written #e&in with a series of .in*lude directives which tell the compiler to fetch certain files and include them in your pro&rams! "ow that we've reached a critical mass and can #e&in writin& our own classes- we will see how to desi&n your own header files! ,t a hi&h level- header files provide a means for e)portin& a class interface without also e)portin& unnecessary implementation details! Cro&rammers who wish to use your class in their code can

Chapter H& Abstraction and Classes

1 ;;D 1

.in*lude the header file containin& your class declaration- and the linker will ensure that the class

implementation is #undled alon& with the final pro&ram! Bore concretely- a header file contains the class declaration Kincludin& #oth $ubli* and $rivate mem#ersL- and the implementation file contains the actual class implementation! 8or e)ample- suppose that we want to e)port the &:Iadio class we've *ust desi&ned in a headerHimplementation pair! 0e'll #e&in #y constructin& the header file! Traditionallyheader files that contain class declarations have the same name as the class and a !h suffi)! 'n our casethis means that we'll #e creatin& a file called &:Iadio.h that contains our class definition! This is shown here= 8ile= &:Iadio.h
.ifndef &:IadioL(n*luded .define &:IadioL(n*luded *lass &:Iadio { $ubli*4 &:Iadio(); &:Iadio(double fre[, int vol); double get&re[uen*%(); void set&re[uen*%(double ne'&re[); int void getJolume(); setJolume(int ne'Jolume);

double set<reset(int inde+, double fre[); bool $resetE+ists(int inde+); double get<reset(int inde+); $rivate4 void void void *he*B&re[uen*%(double fre[); *he*B<reset(int inde+); initialiUe(double fre[, int vol);

#;

double fre[uen*%; int volume; double $resets[N];

.endif

"otice that we've surrounded the header file with an include &uard! 'n case you've for&otten- the include &uard is a way to prevent compiler errors in the event that a client .in*ludes the same file twiceQ see the chapter on the preprocessor for more information! 7eyond this- thou&h- the header contains *ust the class interface! "ow that we've #uilt the !h file for our &:Iadio class- let's see if we can provide a workin& implementation file! Typically- an implementation file will have the same name as the class- suffi)ed with the !cpp e)tension!P ,ppropriately- we'll name this file &:Iadio.*$$! Unlike a !h file- which is desi&ned to e)port the class declaration to clients- the !cpp file *ust contains the implementation of the class! /ere's one possi#le version of the &:Iadio.*$$ file=

P 't is also common to see the !cc e)tension! Glder code mi&ht use the !C e)tension Kcapital CL or the !c++ e)tension!

1 ;;E 1 8ile= &:Iadio.*$$


.in*lude /&:Iadio.h/ &:Iadio44&:Iadio() { initialiUe(FD.H, H); # &:Iadio44&:Iadio(double fre[, int vol) { initialiUe(fre[, vol); # void &:Iadio44initialiUe(double fre[, int vol) { for(siUeLt i = 0; i N; !!i) $resets[i] = 0.0; fre[uen*% = fre[; volume = vol; # void &:Iadio44*he*B&re[uen*%(double fre[) { assert(fre[ )= FD.H ?? fre[ = 80F.F); # void &:Iadio44*he*B<reset(int inde+) { assert(inde+ )= 8 ?? inde+ = N); # double &:Iadio44get&re[uen*%() { return fre[uen*%; # void &:Iadio44set&re[uen*%(double ne'&re[) { *he*B&re[uen*%(ne'&re[); fre[uen*% = ne'&re[; # void &:Iadio44set<reset(int inde+, double fre[) { *he*B<reset(inde+); *he*B&re[uen*%(fre[); $resets[inde+ - 8] = fre[; # bool &:Iadio44$resetE+ists(int inde+) { *he*B<reset(inde+); return $resets[inde+ - 8] == 0.0; # double &:Iadio44get<reset(int inde+) { *he*B<reset(inde+); return $resets[inde+ Q 8]; #

Chapter H& Abstraction and Classes

There are a few important aspects of this !cpp file to note! 8irst- notice that at the top of the file- we .in*luded the !h file containin& the class declaration! This is e4tremely important ( if we don't include the header file for the class- when the C++ compiler encounters the implementations of the class's mem#er functions- it won't have seen the class declaration and will fla& all of the mem#er function implementations as errors! Second- note that when .in*lude1in& the !h file- we surrounded the name of the file in 4dou#le 5uotes6 instead of Van&le #rackets!_ 'f you'll recall- this is #ecause the preprocessor

Chapter H& Abstraction and Classes

1 ;;< 1

treats include directives usin& Van&le #rackets_ as instructions to look for standard li#rary files- and since the classes you'll #e writin& aren't part of the standard li#rary you'll want to use 4dou#le 5uotes6 instead! P "ow that we've partitioned the class into a !hH!cpp pair- we can write pro&rams that use the class without havin& to tediously copy1and1paste the class definition and implementation! 8or e)ample- here's a short pro&ram which manipulates an &:Iadio! "ote that we never actually see the declaration or implementation of the &:Iadio classQ .in*lude1in& the header provides the compiler enou&h information to let us use the &:Iadio!
.in*lude iostream) .in*lude /&:Iadio.h/ using names$a*e std; int main() { &:Iadio m%Iadio; m%Iadio.set&re[uen*%(FF.H); m%Iadio.setJolume(F); "3 ... et*. ... 3" #

Throu&hout the remainder of this #ook- whenever we desi&n and #uild classes- we will assume that the classes are properly partitioned #etween !h and !cpp files! C.a+ter 6ummar/ Software systems are often on the order of millions of lines of code- far lar&er than even the most competent pro&rammers can ever keep track of at once! , sin&le incorrect value in a software system can cause that entire system to fail! The ma)imum num#er of possi#le interactions in a software system &rows e)ponentially in the num#er of components of that system! ,#stractions &ive a way to present a comple) o#*ect in simpler terms! ,#stractions partition users into clients and implementers- each with separate tasks! This separation is sometimes referred to as the wall of a#straction! ,#stractions descri#e many possi#le implementations- and encapsulation prevents clients from peekin& at that implementation! The way in which a client interacts with an o#*ect is called that o#*ect's interface! ,#straction reduces the num#er of components in a software system- reducin& the ma)imum comple)ity of that system! C++ stru*ts lack encapsulation #ecause their implementation is their interface! The C++ class concept is a realization of an interface paired with an implementation!

P 'f you ever have the honor of &ettin& to write a new standard li#rary class- please contact me!!! ''d love to offer comments and su&&estionsR

1 ;@0 1

Chapter H& Abstraction and Classes The mem#ers of a class that are listed pu#lic form that class's interface and are accessi#le to anyone! The mem#ers of a class that are listed private are part of the class implementation and can only #e viewed #y mem#er functions of that class! Constructors allow implementers to enforce invariants from the moment the class is created! Crivate mem#er functions allow implementers to decompose code without revealin& the implementation to clients! Class implementations are traditionally partitioned into a !h file containin& the class definition and a !cpp file containin& the class implementation! 2esi&n class interfaces #efore implementations to avoid overspecializin& the interface on an implementation artifact!

Cractice Cro#lems 1. 'n our discussion of a#straction- we talked a#out how interfaces and modularity can e)ponentially reduce the ma)imum comple)ity of a system! Can you think of any e)amples from the real world where introducin& indirection makes a comple) system more mana&ea#le> 2. 0hat is the motivation #ehind functions alon& the lines of get&re[uen*% and set&re[uen*% over *ust havin& a pu#lic fre5uency data mem#er> 3. 0hen is a constructor invoked> 0hy are constructors useful> 4. 0hat is the difference #etween a pu#lic mem#er function and a private mem#er function> . 0hat &oes in a class's !h file> 'n its !cpp file> !. 0e've talked at len&th a#out the streams li#rary and ST without mentionin& much of how those li#raries are implemented #ehind1the1scenes! J)plain why a#straction makes it possi#le to use these li#raries without full knowled&e of how they work! $. Suppose that C++ were desi&ned somewhat differently in that data mem#ers marked private could only #e read #ut not written to! That is- if a data mem#er called volume were marked private- then clients could read the value #y writin& m%=b>e*t.volume- #ut could not write to the volume varia#le directly! This would prohi#it clients of a class from modifyin& the implementation incorrectly- since any operations that could chan&e the o#*ect's data mem#ers would have to &o throu&h the pu#lic interface! /owever- this setup has a serious desi&n flaw that would make class implementations difficult to chan&e! 0hat is this flaw> 5+int& Thin* bac* to the #olumeDattenuation e4ample $rom earlier6

Chapter H& Abstraction and Classes 6. 7elow is an interface for a class that represents a &rocery list=
*lass Gro*er%7ist { $ubli*4 Gro*er%7ist(); void add(tem(string [uantit%, string item); void remove(tem(string item); string item`uantit%(string item); bool itemE+ists(string item);

1 ;@1 1

#;

The Gro*er%7ist constructor sets the &rocery list to contain no items! The add(tem function adds a certain 5uantity of an item to the &rocery list! 8or e)ample- the call
g7ist.add(tem(/=ne Gallon/, /:ilB/);

would add the item 4Bilk6 to the list with 5uantity 4Gne 3allon!6 'f the item already e)ists in the list- then add(tem should replace the ori&inal 5uantity with the new 5uantity! The remove(tem function should delete the specified item off of the shoppin& list! itemE+ists returns whether the specified item e)ists in the shoppin& list- and item`uantit% takes in an item and returns the 5uantity associated with it in the list! 'f the item doesn't e)ist- item`uantit% can either raise an assert error or return the empty strin&! Crovide an implementation for the Gro*er%7ist class! .ou are free to use whatever implementation you feel is #est- and can implement the mem#er functions as you see fit! /oweveryou mi&ht find it useful to use a ma$ string, string) to represent the items in the list! 7. 0hat is the advanta&e of makin& a Gro*er%7ist class over *ust usin& a raw ma$ string, string)> 10. 2oes the Gro*er%7ist class need a constructor> 0hy or why not> 11. 3ive an e)ample of a parameterized constructor you have encountered in the ST ! 12. 0hy are parameterized constructors useful> 13. Keno is a popular &am#lin& &ame with similarities to a lottery or #in&o! Clayers place a #et and pick a set of num#ers #etween 1 and E0- inclusive! The num#er of num#ers chosen can #e anywhere from one to twenty- with each havin& a different payoff scale! Gnce the players have chosen their num#ers- twenty random num#ers #etween 1 and E0 are chosen- and players receive a payoff #ased on how many num#ers they picked that matched the chosen num#ers! 8or e)ampleif a player picked five num#ers and all five were chosen- she mi&ht win around c1-000 for a one1 or two1dollar #et! The actual payoffs are #ased on the pro#a#ilities of hittin& * num#ers out of n chosen- #ut this is irrelevant for our discussion! Suppose that you are interested in writin& a pro&ram that lets the user play Keno! .ou are not interested in the payoffs- *ust lettin& the user enter num#ers and reportin& which of the user's num#ers came up! To do this- you decide to write a class WenoGame with the followin& interfaces=

1 ;@; 1
*lass WenoGame { $ubli*4 WenoGame(); void addKumber(int value); siUeLt num5hosen(); siUeLt num2inners(ve*tor int)? values); #;

Chapter H& Abstraction and Classes

The WenoGame constructor initializes the class however you see fit! addKumber takes in a num#er from the user and adds it to the set of num#ers the user &uessed! The num5hosen mem#er function returns how many num#ers the user has picked so far! 8inally- the num2inners function takes in a ve*tor int) correspondin& to the num#ers that were chosen and returns how many of the user's num#ers were winners! 0rite an implementation of the WenoGame class! 14. Fefer #ack to the implementation of ,na*e from the chapter on ST containers! 2esi&n and implement a class that represents a snake! 0hat operations will you support in the pu#lic interface> /ow will you implement it>

Chapter 9: Refining Abstractions

_________________________________________________________________________________________________________

'n the previous chapter- we e)plored the class concept and saw how to use classes to model an interface paired with an implementation! .ou learned how to realize the idealized versions of a#straction and encapsulation usin& the $ubli* and $rivate keywords- as well as how to use constructors to enforce class invariants! /owever- our tour of classes has *ust #e&un- and there are many nuances of class desi&n we have yet to address! 8or e)ample- since class clients cannot look at the class implementation- how can they tell which parts of the pu#lic interface are desi&ned to read the class's state and which parts will write it> /ow can you more accurately control how constructors initialize data> ,nd how can you share data across all instances of a class> These 5uestions are all essentially variants on a common theme= how can we refine our a#stractions to make them more precise> This chapter e)plores some of C++'s lan&ua&e features that allow you as a pro&rammer to more clearly communicate your intentions when desi&nin& classes! The tools you will learn in this chapter will follow you throu&h the rest of your pro&rammin& career- and appreciatin& e)actly where each is applica#le will &ive you a si&nificant advanta&e when desi&nin& software! !arameteri5ing Classes wit. Tem+lates Gne of the most important lessons an upstart computer scientist or software en&ineer can learn is decomposition or $actoring ( #reakin& pro#lems down into smaller and smaller pieces and solvin& each su#pro#lem separately! ,t the heart of decomposition is the concept of generality ( code should avoid overspecializin& on a sin&le pro#lem and should #e ro#ust enou&h to adapt to other situations! Take as an e)ample the ST ! Father than specializin& the ST container classes on a sin&le type- the authors decided to parameterize the containers over the types they store! This means that the code written for the ve*tor class can #e used to store almost any type- and the ma$ can use ar#itrary types as keyHvalue pairs! Similarly- the ST al&orithms were desi&ned to operate on all types of iterators rather than on specific container classes- makin& them fle)i#le and adapta#le! The ST is an e)cellent e)ample of how versatile- fle)i#le- and powerful C++ templates can #e! 'n C++ a template is *ust that ( a code pattern that can #e instantiated to produce a type or function that works on an ar#itrary type! Up to this point you've primarily #een a client of template code- and now it's time to &ear up to write your own templates! 'n this section we'll cover the #asics of templates and &ive a 5uick tour of how template classes operate under the hood! 0e will make e)tensive use of templates later in this te)t and especially in the e)tended e)amples- and hopefully #y the time you've finished readin& this #ook you'll have an appreciation for *ust how versatile templates can #e! Class Tem+lates 'n C++- a class template is a class that- like the ST ve*tor or ma$- is parameterized over some num#er of types! 'n a sense- a class template is a class with a hole in it! 0hen a client uses a template class- she fills in these holes to yield a complete type! .ou have already seen this with the ST containers= you cannot create a varia#le of type ve*tor or ma$- thou&h you can create a varia#le of type ve*tor int) or ma$ string, string)! Class templates are most commonly used to create types that represent particular data structures! 8or e)ample- the ve*tor class template is an implementation of a linear se5uence usin& a dynamically1 allocated array as an implementation! The operations that maintain the dynamic array are more or less

1 ;@A 1

Chapter ;& Ge$ining Abstractions

independent of the type of elements in that array! 7y writin& ve*tor as a class template rather than a concrete class- the desi&ners of the ST make it possi#le to use linear se5uences of ar#itrary C++ types! Gf course- not all classes should #e written as class templates! 8or e)ample- the &:Iadio class from the previous chapter is an unlikely candidate for a class template #ecause it does not hold a collection of data that could #e of ar#itrary type! ,lthou&h &:Iadio does hold multiple pieces of data Knota#ly the radio's presetsL- those presets are always radio fre5uencies- which we've encoded with doubles! 't would not make sense for the &:Iadio's presets to #e stored as ve*tor int)s- nor as strings! ,s a &eneral rulemost classes don't need to #e written as class templates! Defining a Class Tem+late Gnce you've decided that the class you're writin& is #est parameterized over some ar#itrary type- you can indicate to C++ that you're definin& a template class #y usin& the tem$late keyword and specifyin& what types the template should #e parameterized over! 8or e)ample- suppose that we want to define our own version of the $air struct used #y the ST ! 'f we want to call this struct :%<air and have it #e parameterized over two types- we can write the followin&=
tem$late t%$ename &irst;%$e, t%$ename 6e*ond;%$e) stru*t :%<air { &irst;%$e first; 6e*ond;%$e se*ond; #;

/ere- the synta) tem$late t%$ename &irst;%$e, t%$ename 6e*ond;%$e) indicates to C++ that what follows is a class template that is parameterized over two types- one called &irst;%$e and one called 6e*ond;%$e! 'n many ways- type ar&uments to a class template are similar to re&ular ar&uments to C++ functions! 8or e)ample- the actual names of the parameters are unimportant as far as clients are concerned- much in the same way that the actual names of parameters to functions are unimportant! The a#ove definition is functionally e5uivalent to this one #elow=
tem$late t%$ename =ne, t%$ename ;'o) stru*t :%<air { =ne first; ;'o se*ond; #;

0ithin the #ody of the class template- we can use the names =ne and ;'o Kor &irst;%$e and 6e*ond;%$eL to refer to the types that the client specifies when she instantiates :%<air- much in the same way that parameters inside a function correspond to the values passed into the function #y its caller! 'n this a#ove e)ample- we used the t%$ename keyword to introduce a type ar&ument to a class template! 'f you work on other C++ code #ases- you mi&ht see the a#ove class template written as follows=
tem$late *lass &irst;%$e, *lass 6e*ond;%$e) stru*t :%<air { &irst;%$e first; 6e*ond;%$e se*ond; #;

'n this instance- t%$ename and *lass are completely e5uivalent to one another! /owever- ' find the use of *lass misleadin& #ecause it incorrectly implies that the parameter must #e a class type! This is not the case ( you can still instantiate templates that are parameterized usin& *lass with primitive types like int or double! 8rom here on out- we will use t%$ename instead of *lass!P
P .ou can only su#stitute t%$ename keyword!
*lass

for

t%$ename

in this instance ( it's ille&al to declare a re&ular C++ class usin& the

Chapter ;& Ge$ining Abstractions

1 ;@? 1

To create an instance of :%<air specialized over some particular types- we specify the name of the class template- followed #y the type ar&uments surrounded #y an&le #rackets! 8or e)ample=
:%<air int, string) one; "" A $air of an int and a string. one.first = 8CD; one.se*ond = /;em$lates are *ool1/;

This synta) should hopefully #e familiar from the ST ! Classes and stru*ts are closely related to one another- so unsurprisin&ly the synta) for declarin& a template class is similar to that for a template stru*t! et's suppose that we want to convert our :%<air stru*t into a class with full encapsulation Ki!e! with accessor methods and constructors instead of e)posed data mem#ersL! Then we would #e&in #y declarin& :%<air as
tem$late t%$ename &irst;%$e, t%$ename 6e*ond;%$e) *lass :%<air { $ubli*4 "3 ... 3" $rivate4 &irst;%$e first; 6e*ond;%$e se*ond; #;

"ow- what sorts of functions should we define for our :%<air class> 'deally- we'd like to have some way of accessin& the elements stored in the pair- so we'll define a pair of functions get&irst and set&irst alon& with an e5uivalent get6e*ond and set6e*ond! This is shown here=
tem$late t%$ename &irst;%$e, t%$ename 6e*ond;%$e) *lass :%<air { $ubli*4 &irst;%$e get&irst(); void set&irst(&irst;%$e ne'Jalue); 6e*ond;%$e get6e*ond(); void set6e*ond(6e*ond;%$e ne'Jalue); $rivate4 &irst;%$e first; 6e*ond;%$e se*ond; #;

"otice that we're usin& the template ar&uments &irst;%$e and 6e*ond;%$e to stand for whatever types the client parameterizes :%<air over! 0e don't need to indicate that &irst;%$e and 6e*ond;%$e are at all different from other types like int or string- since the C++ compiler already knows that from the tem$late declaration! 'n fact- with a few minor restrictions- once you've defined a template ar&umentyou can use it anywhere that an actual type could #e used and C++ will understand what you mean! "ow that we've declared these functions- we should &o a#out implementin& them in the intuitive way! 'f :%<air were not a template class- we could write the followin&=
&irst;%$e :%<air44get&irst() { "" 1roblem4 Kot legal s%nta+ return first; #

1 ;@6 1

Chapter ;& Ge$ining Abstractions

The pro#lem with this a#ove code is that :%<air is a class template- not an actual class! 'f we don't tell C++ that we're tryin& to implement a mem#er function for a class template- the compiler won't understand what we mean! Thus the proper way to implement this mem#er function is
tem$late t%$ename &irst;%$e, t%$ename 6e*ond;%$e) &irst;%$e :%<air &irst;%$e, 6e*ond;%$e)44get&irst() { return first; #

/ere- we've e)plicitly prefaced the implementation of get&irst with a template declaration and we've marked that the mem#er function we're implementin& is for :%<air &irst;%$e, 6e*ond;%$e)! The template declaration is necessary for C++ to fi&ure out what &irst;%$e and 6e*ond;%$e mean heresince without this information the compiler would think that &irst;%$e and 6e*ond;%$e were actual types instead of placeholders for types! That we've mentioned this function is availa#le inside :%<air &irst;%$e, 6e*ond;%$e) instead of *ust :%<air is also mandatory since there is no real :%<air class ( after all- :%<air is a class template- not an actual class! The other mem#er functions can #e implemented similarly! 8or e)ample- here's an implementation of set6e*ond=
tem$late t%$ename &irst;%$e, t%$ename 6e*ond;%$e) void :%<air &irst;%$e, 6e*ond;%$e)44set6e*ond(6e*ond;%$e ne'Jalue) { se*ond = ne'Jalue; #

0hen implementin& mem#er functions for template classes- you do not need to repeat the template definition if you define the function inside the #ody of the template class! Thus the followin& code is perfectly le&al=
tem$late t%$ename &irst;%$e, t%$ename 6e*ond;%$e) *lass :%<air { $ubli*4 &irst;%$e get&irst() { return first; # void set&irst(&irst;%$e ne'Jalue) { first = ne'Jalue; # 6e*ond;%$e get6e*ond() { return se*ond; # void set6e*ond(6e*ond;%$e ne'Jalue) { se*ond = ne'Jalue; # $rivate4 &irst;%$e first; 6e*ond;%$e se*ond; #;

The reason for this is that inside of the class template- the compiler already knows that &irst;%$e and 6e*ond;%$e are templates- and it's not necessary to remind it!

Chapter ;& Ge$ining Abstractions

1 ;@D 1

"ow- let's suppose that we want to define a mem#er function called s'a$ which accepts as input a reference to another :%<air class- then swaps the elements in that :%<air with the elements in the receiver o#*ect! Then we can prototype the function like this=
tem$late t%$ename &irst;%$e, t%$ename 6e*ond;%$e) *lass :%<air { $ubli*4 &irst;%$e get&irst() { return first; # void set&irst(&irst;%$e ne'Jalue) { first = ne'Jalue; # 6e*ond;%$e get6e*ond() { return se*ond; # void set6e*ond(6e*ond;%$e ne'Jalue) { se*ond = ne'Jalue; # void s'a$(:%<air? other); $rivate4 &irst;%$e first; 6e*ond;%$e se*ond; #;

Jven thou&h :%<air is a template class parameterized over two ar&uments- inside the #ody of the :%<air template class definition we can use the name :%<air without mentionin& that it's a :%<air &irst;%$e, 6e*ond;%$e)! This is perfectly le&al C++ and will come up more when we #e&in discussin& copyin& #ehavior in a few chapters! The actual implementation of s'a$ is left as an e)ercise! .. and .c++ files for tem+late classes 0hen writin& a C++ class- you normally partition the class into two files= a !h file containin& the declaration and a !cpp file containin& the implementation! The C++ compiler can then compile the code contained in the !cpp file and then link it into the rest of the pro&ram when needed! 0hen writin& a template class- however- #reakin& up the definition like this will cause linker errors! The reason is that C+ + templates are *ust that ( they're templates for C++ code! 0henever you write code that instantiates a template class- C++ &enerates code for the particular instance of the class #y replacin& all references to the template parameters with the ar&uments to the template! 8or e)ample- with the :%<air class defined a#ove- if we create a :%<air int, string)- the compiler will &enerate code internally that looks like this=
*lass :%<air int, string) { $ubli*4 int get&irst(); void set&irst(int ne'Jalue); string get6e*ond(); void set6e*ond(string ne'Jalue); $rivate4 int first; string se*ond; #

1 ;@E 1

Chapter ;& Ge$ining Abstractions

Chapter ;& Ge$ining Abstractions


int :%<air int, string)44get&irst() { return first; # void :%<air int, string)44set&irst(int ne'Jalue) { first = ne'Jalue; # string :%<air int, string)44get6e*ond() { return se*ond; # void :%<air int, string)44set6e*ond(string ne'Jalue) { se*ond = ne'Jalue; #

1 ;@< 1

,t this point- compilation continues as usual! 7ut what would happen if the compiler didn't have access to the implementation of the :%<air class> That is- let's suppose that we've created a header file- m%-$air.h- that contains only the class declaration for :%<air- as shown here= File& my-pair.h
.ifndef :%<airL(n*luded "" (n*lude guard $revents multi$le in*lusions .define :%<airL(n*luded tem$late t%$ename &irst;%$e, t%$ename 6e*ond;%$e) *lass :%<air { $ubli*4 &irst;%$e get&irst(); void set&irst(&irst;%$e ne'Jalue); 6e*ond;%$e get6e*ond(); void set6e*ond(6e*ond;%$e ne'Jalue)E $rivate4 &irst;%$e first; 6e*ond;%$e se*ond; #; .endif

Suppose that we have a file that .in*ludes the m%-$air.h file and then tries to use the :%<air class! Since all that the compiler has seen of :%<air is the a#ove class definition- the compiler will only &enerate the followin& code for :%<air=
*lass :%<air int, string) { $ubli*4 int get&irst(); void set&irst(int ne'Jalue); string get6e*ond(); void set6e*ond(string ne'Jalue); $rivate4 int first; string se*ond; #

1 ;A0 1

Chapter ;& Ge$ining Abstractions

"otice that while all the mem#er functions of :%<air int, string) have #een prototyped- they haven't #een implemented #ecause the compiler didn't have access to the implementations of each of these mem#er functions! 'n other words- if a template class is instantiated and the compiler hasn't seen implementations of its mem#er functions- the resultin& template class will have no code for its mem#er functions! This means that the pro&ram won't link- and our template class is now useless! 0hen writin& a template class for use in multiple files- the entire class definition- includin& implementations of mem#er functions- must #e visi#le in the header file! Gne way of doin& this is to create a !h file for the template class that contains #oth the class definition and implementation without creatin& a matchin& !cpp file! This is the approach adopted #y the C++ standard li#raryQ if you open up any of the headers for the ST - you'll find the complete Kand crypticL implementations of all of the functions and classes e)ported #y those headers! To &ive a concrete e)ample of this approach- here's what the m%-$air.h header file mi&ht look like if it contained #oth the class and its implementation= File& my-pair.h
"3 ;his method of $a*Baging the .h".*$$ $air $uts the entire *lass definition and 3 im$lementation into the .h file. ;here is no .*$$ file for this header. 3" .ifndef :%<airL(n*luded .define :%<airL(n*luded tem$late t%$ename &irst;%$e, t%$ename 6e*ond;%$e) *lass :%<air { $ubli*4 &irst;%$e get&irst(); void set&irst(&irst;%$e ne'Jalue); 6e*ond;%$e get6e*ond(); void set6e*ond(6e*ond;%$e ne'Jalue)E $rivate4 &irst;%$e first; 6e*ond;%$e se*ond; #; tem$late t%$ename &irst;%$e, t%$ename 6e*ond;%$e) &irst;%$e :%<air &irst;%$e, 6e*ond;%$e)44get&irst() { return first; # tem$late t%$ename &irst;%$e, t%$ename 6e*ond;%$e) void :%<air &irst;%$e, 6e*ond;%$e)44set&irst(&irst;%$e ne'Jalue) { first = ne'Jalue; # tem$late t%$ename &irst;%$e, t%$ename 6e*ond;%$e) 6e*ond;%$e :%<air &irst;%$e, 6e*ond;%$e)44get6e*ond() { return se*ond; # tem$late t%$ename &irst;%$e, t%$ename 6e*ond;%$e) void :%<air &irst;%$e, 6e*ond;%$e)44set6e*ond(6e*ond;%$e ne'Jalue) { se*ond = ne'Jalue; # .endif

Chapter ;& Ge$ining Abstractions

1 ;A1 1

Cuttin& the class and its definition inside the header file is a valid way to prevent linker errors- #ut it seems to violate the principle of separation of interface and implementation! ,fter all- the reason we have #oth !h and !cpp files is to hide a class implementation in a file that clients never have to look at! Unfortunately- #arrin& some particularly unsi&htly and hacky a#uses of the preprocessor- you will need to structure template code in this manner! T.e Two (eanings of typename Gne of the more unfortunate 5uirks of the C++ lan&ua&e is the dual meanin& of the t%$ename keyword! ,s mentioned previously- when definin& a template class- you can the t%$ename keyword to declare type parameters for the template class! /owever- there is another use of the t%$ename keyword that can easily catch you off &uard unless you're on the lookout for it! Suppose- for e)ample- that we wish to implement a class akin to the ST sta*B which represents a '8G container! 7ecause the a#stract notion of a stack only concerns the ordering of the elements in the container rather than the type or contents of the elements in the container- we should pro#a#ly consider implementin& the stack as a template class! /ere is one possi#le interface for such a class- which we'll call 6ta*B to differentiate it from the ST sta*B=
tem$late t%$ename ;) *lass 6ta*B { $ubli*4 void $ush(; value); ; $o$(); siUeLt siUe(); bool em$t%();

#;

There are many ways that we could implement this 6ta*B class= we could use dynamically1allocated arrays- or the ST ve*tor or de[ue containers! Gf these three choices- the ve*tor and de[ue are certainly simpler than usin& dynamically1allocated arrays! Boreover- since all of the additions and deletions from a stack occur at the end of the container- the de[ue is pro#a#ly a more suita#le container with which we could implement our 6ta*B! 0e'll therefore implement the 6ta*B usin& a de[ue- as shown here=
tem$late t%$ename ;) *lass 6ta*B { $ubli*4 void $ush(; value); ; $o$(); siUeLt siUe(); bool em$t%(); $rivate4 de[ue ;) elems; #;

"otice that we've used the template parameter ; to parameterize the de[ue! This is perfectly valid- and is 5uite common when implementin& template classes! 3iven this implementation strate&y- we can implement each of the mem#er functions as follows! Bake sure that you can read this codeQ it's fairly template1dense!

1 ;A; 1
tem$late t%$ename ;) void 6ta*B ;)44$ush(; value) { elems.$ushLfront(value); # tem$late t%$ename ;) ; 6ta*B ;)44$o$() { ; result = elems.front(); elems.$o$Lfront(); return result; # tem$late t%$ename ;) siUeLt 6ta*B ;)44siUe() { return elems.siUe(); # tem$late t%$ename ;) bool 6ta*B ;)44em$t%() { return elems.em$t%(); #

Chapter ;& Ge$ining Abstractions

This is a perfectly reasona#le implementation of a stack- and in fact the ST sta*B implementation is very similar to this one! "ow- suppose that we're interested in e)tendin& the functionality of the 6ta*B so that class clients can iterate over the elements of the 6ta*B in the order that they will #e removed! 8or e)ample- if we push the elements 1- ;- @- A- ? onto the stack- the iteration would visit the elements in the order ?- A- @- ;- 1! This functionality is usually not found on a 6ta*B- #ut is useful for de#u&&in& Ke!&! printin& out the contents of the stackL or modifyin& the elements of the 6ta*B after they've already #een inserted! To do this- we'll need to add begin() and end() functions to the 6ta*B class that return iterators over the underlyin& de[ue! 7ecause the internal de[ue is a de[ue ;)- these iterators have type de[ue ;)44iterator! Conse5uently- you mi&ht think that we would update the interface as follows=
tem$late t%$ename ;) *lass 6ta*B { $ubli*4 void $ush(; value); ; $o$(); siUeLt siUe(); bool em$t%(); de[ue ;)44iterator begin(); "" 1roblem4 (llegal s%nta+. de[ue ;)44iterator end(); "" 1roblem4 (llegal s%nta+. $rivate4 de[ue ;) elems; #;

This code is perfectly well1intentioned- #ut unfortunately is not le&al C++ code! The pro#lem has to do with the fact that de[ue ;) is a dependent type- a type that 4depends6 on a template parameter! 'ntuitively- this is #ecause de[ue ;) isn't a concrete type ( it's a pattern that says 4once you &ive me the type ;- ''ll &ive you #ack a de[ue of ;'s6! 2ue to a somewhat arcane restriction in the C++ lan&ua&e- if you try to access a type nested inside of a dependent type inside of a template class Kfor e)ample- tryin& to use the iterator type nested inside de[ue ;)L- you must preface that type with the t%$ename keyword! The correct version of the 6ta*B class is as follows=

Chapter ;& Ge$ining Abstractions


tem$late t%$ename ;) *lass 6ta*B { $ubli*4 void $ush(; value); ; $o$(); siUeLt siUe(); bool em$t%(); t%$ename de[ue ;)44iterator begin(); "" Ko' *orre*t t%$ename de[ue ;)44iterator end(); "" Ko' *orre*t $rivate4 de[ue ;) elems; #;

1 ;A@ 1

This syntactic oddity is one of the truly em#arrassin& parts of C++! There is no hi&h1level reason why t%$ename should #e necessary- and its e)istence is a perpetual source of confusion and frustration amon& new C++ pro&rammers! ' wholeheartedly wish that ' could &ive you a nice clean e)planation as to why t%$ename is necessary- #ut the real answer is hi&hly technical and in many ways unsatisfactory! Gf coursethis doesn't e)cuse you from havin& to put the t%$ename keyword in when it's necessary- and you'll have to make sure to use it where appropriate! The &ood news is that t%$ename is unnecessary in most circumstances! .ou only need to use the t%$ename keyword when accessin& a type nested inside of a dependent type! 8rom a practical standpoint- this means that if you want to look up a type nested inside of a type that's either a template parameter or is parameterized over a template parameter- you must preface the type with the t%$ename keyword! 'n the e)amples used in the upcomin& chapters- this will only occur when lookin& up iterators inside of ST containers that themselves are parameterized over a template ar&ument- such as a de[ue ;)44iterator or a ve*tor ;)44iterator! To complete the a#ove e)ample- the implementation of the begin and end functions are shown here=
tem$late t%$ename ;) t%$ename de[ue ;)44iterator 6ta*B ;)44begin() { return elems.begin(); # tem$late t%$ename ;) t%$ename de[ue ;)44iterator 6ta*B ;)44end() { return elems.end(); #

These functions mi&ht #e the densest pieces of code you've encountered so far! The code tem$late t%$ename ;) declares that the mem#er function implementation is an implementation of a template class's mem#er function! t%$ename de[ue ;)44iterator is the return type of the function- and 6ta*B ;)44begin() is the name of the mem#er function and the KemptyL parameter list! 0hen writin& template classes- code like this is fairly u#i5uitous- #ut with practice you'll #e a#le to read this code much more easily! Clarif/ing Interfaces wit. const ,t its core- C++ is a lan&ua&e #ased on modifyin& pro&ram state! ints &et incremented in for loopsQ ve*tors have innumera#le calls to *lear- resiUe- and $ushLba*BQ and console 'HG overwrites varia#les with values read directly from the user! Consider the followin& function=

1 ;AA 1

Chapter ;& Ge$ining Abstractions

void 7oad&ile5ontents(string filename, ve*tor string)? out) { ifstream in$ut(filename.*Lstr()); "" =$en the file out.*lear(); string line; 'hile (getline(in$ut, line)) out.$ushLba*B(line);

This function takes in a strin& containin& the name of a file- then reads the contents of the file into a ve*tor string) specified as a reference parameter! 7ecause this function writes the result to an e4isting ve*tor rather than creatin& a new ve*tor for output- we say that the function has side e$$ects! Side effects are e)tremely common in C++ code- and in fact without side effects C++ pro&rams would #e very difficult to write! /owever- when workin& with increasin& lar&e software systems- side effects can #e dan&erous! ,s mentioned last chapter- a sin&le incorrect #it can take down an entire software system! Conse5uently- you must #e very careful when desi&nin& functions with side effects so that the scope of what those side effects can modify is minimized! To see e)actly why this is- let's consider the e)treme case! Suppose every function in a pro&ram is allowed to modify any piece of data in the pro&ram! That iswhenever a function is called- the values of all varia#les in all functions mi&ht #e chan&ed! 0hat would this mean for pro&rammin&> Certainly- it would #e much more difficult to reason a#out how pro&rams operate! Consider- for e)ample- the followin& loop=
for (siUeLt B = 0; B :%&un*tion(); 800; !!B)

/ere- we iterate over the first one hundred inte&ers- callin& some function called :%&un*tion! 0hat will this pro&ram do> Certainly it depends on the implementation of :%&un*tion- #ut a reasona#le pro&rammer would pro#a#ly infer that :%&un*tion will #e called e)actly one hundred times! 7ut this is makin& the reasona#le assumption that #ecause :%&un*tion isn't passed B as a parameter- it has no way of modifyin& the local varia#le B in the callin& function! /owever- we're assumin& that functions are allowed to modify any data in the pro&ram! 3iven this assumption- there's no reason that the :%&un*tion function couldn't chan&e the value of B whenever it's called! 't mi&ht- for e)ample- set B to #e 0 on every iteration- meanin& that the loop will never terminate Ksee if you can convince yourself why this isL! Similarly- the function mi&ht increment B #y one every time it's called- causin& the loop to e)ecute half as many times as it should Ksince B will take on values 0- ;- A- E- !!! instead of 0- 1- ;- @- !!!L! 0ithout lookin& at the implementation of :%&un*tion- there would #e no way to know e)actly what will happen to B! Tryin& to infer what the pro&ram will do #y lookin& at its complete source code would #e su#stantially more complicated- and #uildin& pro&rams more than a few hundred lines of code would 5uickly #ecome difficult or impossi#le! /opefully the a#ove e)ample has convinced you that allowin& functions to make ar#itrary chan&es to pro&ram state is not a via#le option! 8ortunately- C++ is specifically desi&ned to allow pro&rammers to constrain where data can #e modified! Bany of the pro&rammin& concepts we've e)plored so far revolve around this idea! 8or e)ample= A;oiding global ;ariables! .ou have pro#a#ly #een hammered repeatedly with the idea that &lo#al varia#les can #e hazardous! 3lo#al varia#les make pro&rams si&nificantly harder to maintain #ecause &lo#als can #e modified #y any function- at any time- for any reason! This means that if a pro&ram encounters an error #ecause a &lo#al varia#le has an incorrect value- it is difficult to track down e)actly where in the pro&ram that varia#le received the incorrect value! 7y usin& local varia#les instead of &lo#als- it is easier to track down e)actly where errors occur #y followin& which functions have access to those varia#les!

Chapter ;& Ge$ining Abstractions

1 ;A? 1

(arking data members pri#ate! 0e initially e)plored encapsulation from a theoretical perspective as a means for separatin& implementation from interface! /owever- encapsulation also helps control where side effects can occur in a pro&ram! 'f a class's data mem#ers are marked $rivate- then any chan&es to those data mem#ers must result from the class's pu#lic interface! Terifyin& that the class's interface is implemented correctly can therefore increase confidence that data mem#ers aren't mercilessly clo##ered! Decom+osing large functions! 7esides makin& code cleaner- more maintaina#le- and easier to follow- decomposition minimizes the amount of code that has access to each local varia#le! 'f a task is well1decomposed- then each function will have access only to a small num#er of varia#les and thus cannot affect much pro&ram state!

Jach of these pro&rammin& patterns ensure that data can only #e modified in places where a pro&rammer has e)plicitly &ranted particular functions access to that data! /owever- C++ provides an even stron&er mechanism for preventin& une)pected side effects ( the *onst keyword! .ou have already seen *onst in the conte)t of &lo#al constants- #ut the *onst keyword has many other uses! This section introduces the mechanics of *onst Kfor e)ample- where *onst can #e used and what it means in these conte)tsL and how to use it properly in C++ code! const Kariables So far- you've only seen *onst in the conte)t of &lo#al constants! 8or e)ample- &iven the followin& &lo#al declaration=
*onst int :%5onstant = 8CD;

0henever you refer to the value :%5onstant in code- the compiler knows that you're talkin& a#out the value 1@D! 'f later in your pro&ram you were to write :%5onstant = GE- the complier would fla& the line as an error #ecause code to this effect modifies a value you e)plicitly indicated should never #e modified! /owever- *onst is not limited to &lo#al constants! .ou can also declare local varia#les *onst to indicate that their values should never chan&e! Consider the followin& code snippet=
for (set int)44iterator itr = m%6et.lo'erLbound(GE); itr 1= m%6et.u$$erLbound(8CD); !!itr) { "3 ... mani$ulate 3itr ... 3" #

This code iterates over all of the values in an ST set whose values are in the ran&e NA;- 1@DO! P /oweverthis code is not nearly as efficient as it could #e! 7ecause C++ evaluates the loopin& condition of a for loop on each iteration- the pro&ram will evaluate the statement itr 1= m%6et.u$$erLbound(8CD) once per loop iteration- so the pro&ram will recompute m%6et.u$$erLbound(8CD) multiple times! ,lthou&h the ST set is hi&hly optimized and the u$$erLbound function is particularly fast Kon a set with n elementsupper[bound runs in time proportional to lo& ; nL- if there are many elements in the ran&e NA;- 1@DO the overhead of multiple calls to u$$erLbound may #e noticea#le! To fi) this- we mi&ht consider computin& m%6et.u$$erLbound e)actly once- storin& the value somewhere- and then referencin& the precomputed value inside the for loop! /ere's one possi#le implementation=
set int)44iterator sto$ = m%6et.u$$erLbound(8CD); for (set int)44iterator itr = m%6et.lo'erLbound(GE); itr 1= sto$; !!itr) { "3 ... mani$ulate 3itr ... 3" # P 'f you're a #it rusty on the containers!
u$$erLbound

and

lo'erLbound

functions- refer #ack to the chapter on ST associative

1 ;A6 1

Chapter ;& Ge$ining Abstractions

This version of the loop will run much faster than its previous incarnation! /owever- this new version of the loop now depends on the fact that sto$ holds the value of m%6et.u$$erLbound(8CD) throu&hout the loop! 'f we accidentally overwrite sto$- we'll end up iteratin& the wron& num#er of times! 'n other wordsthe varia#le sto$ isn't really a varia#le ( it shouldn't vary ( #ut instead should #e a constant! To indicate to C++ that the value of sto$ shouldn't chan&e- we can mark the sto$ varia#le *onst! This prevents us from chan&in& the value of sto$- and will cause a compile1time error if we try to do so! The updated code is shown here=
*onst set int)44iterator sto$ = m%6et.u$$erLbound(8CD); for (set int)44iterator itr = m%6et.lo'erLbound(GE); itr 1= sto$; !!itr) { "3 ... mani$ulate 3itr ... 3" #

This is your first &limpse of a *onst local varia#le! *onst local varia#les are similar to &lo#al constants= they must #e initialized to a value- their values can't chan&e durin& the course of e)ecution- etc! 'n fact- the only difference #etween a *onst local varia#le and a &lo#al constant is scope! 3lo#al constants are &lo#ally visi#le and persist throu&hout the course of a pro&ram- while *onst local varia#les are created and destroyed like re&ular local varia#les! const $b%ects The main idea #ehind *onst is to let pro&rammers communicate that the values of certain varia#les should not chan&e durin& pro&ram e)ecution! 0hen workin& with primitive types- the meanin& of 4should not chan&e6 is fairly clear= an int chan&es if it is incremented- decremented or overwrittenQ a bool chan&es if it flips from true to falseQ etc! /owever- when workin& with varia#les of class type- our notion of 4should not chan&e6 #ecomes su#stantially more nuanced! To &ive you a sense for why this is- let's consider a *onst string- a C++ string whose contents cannot #e modified! 0e can declare a *onst string as we would any other *onst varia#le! 8or e)ample=
*onst string m%6tring = /;his is a *onstant string1F;

"ote that- like all *onst varia#les- we are still allowed to assi&n the string an initial value! 7ecause the string is *onst- we're not allowed to modify its contents- #ut we can still perform some #asic operations on it! 8or e)ample- here's some code that prints out the contents of a *onst string=
*onst string m%6tring = /;his is a *onstant string1/; for(siUeLt i = 0; i m%6tring.length(); !!i) *out m%6tring[i] endl;

To us humans- the a#ove code seems completely fine and indeed it is le&al C++ code! 7ut how does the compiler know that the length function doesn't modify the contents of the string> This 5uestion may seem silly ( of course the length function won't chan&e the len&th of the strin& ( #ut this is only o#vious #ecause we humans have a &ut feelin& a#out how a function called length should #ehave! The compileron the other hand- knows nothin& of natural lan&ua&e- and could care less whether the function were named 4length6 or 4U%UU%U$l%+!6 This raises a natural 5uestion= &iven an ar#itrary class- how can the compiler tell which mem#er functions mi&ht modify the receiver o#*ect and which ones cannot> To answer this 5uestion- let's look at the prototype for the string mem#er function length=P

P The actual implementation of the string class looks very different from this #ecause strin& is a class template rather than an actual class! 8or our discussion- thou&h- this simplification is perfectly valid!

Chapter ;& Ge$ining Abstractions


*lass string { $ubli*4 siUeLt length() *onst; #; "3 ... et*. ... 3"

1 ;AD 1

"ote that there is a *onst after the mem#er function declaration! This is another use of the *onst keyword that indicates that the mem#er function does not modify any of the class's instance varia#les! That is- when callin& a *onst mem#er function- you're &uaranteed that the o#*ect's contents cannot chan&e! KThis isn't technically true- as you'll see later- #ut it's a perfectly valid way of thinkin& a#out *onst functionsL! 0hen workin& with *onst o#*ects- you are only allowed to call mem#er functions on that o#*ect that have #een e)plicitly marked *onst! That is- even if you have a function that doesn't modify the o#*ect- unless you tell the compiler that the mem#er function is *onst- the compiler will treat it as a non1*onst function! This may seem like a nuisance- #ut has the advanta&e that it forces you to decide whether or not a mem#er function should #e *onst #efore you #e&in implementin& it! That is- the *onstness of a mem#er function is an inter$ace desi&n decision- not an implementation desi&n decision! To see how *onst mem#er functions work in practice- let's consider a simple <oint class that stores a point in two1dimensional space! Usin& the &etterHsetter paradi&m- we end up with this class definition=
*lass <oint { $ubli*4 <oint(double +, double %); double getR(); double getS(); void setR(double ne'R); void setS(double ne'S); $rivate4 double +, %; #;

et's take a minute to think a#out which of these functions should #e *onst and which should not #e! Clearly- the setR and setS functions should not #e *onst- since these operations #y their very nature modify the receiver o#*ect! 7ut what a#out getR and getS> "either of these functions should modify the receiver o#*ect- since they're desi&ned to let clients 5uery the o#*ect's internal state! 0e should therefore mark these functions *onst to indicate that they cannot modify the o#*ect! This &ives us the followin& definition of <oint=

1 ;AE 1
*lass <oint { $ubli*4 <oint(double +, double %); double getR() *onst; double getS() *onst; void setR(double ne'R); void setS(double ne'S); $rivate4 double +, %; #;

Chapter ;& Ge$ining Abstractions

There's only one function we've i&nored so far ( the <oint constructor! /owever- in C++ it's ille&al to mark a constructor *onst- since the typical operation of a constructor runs contrary to the notion of *onst! Take a minute to think a#out why this isQ you'll #e a #etter C++ coder for itR "ow that we've marked the getR and getS functions *onst- we can think a#out how we mi&ht &o a#out implementin& these functions! .ou mi&ht think that we would implement them *ust as we would re&ular mem#er functions- and you would almost #e ri&ht! /owever- the fact that the function is *onst is part of that function's si&nature- and so in the implementation of the getR and getS functions we will need to e)plicitly indicate that those mem#er functions are *onst! /ere is one possi#le implementation of getRQ similar code can #e written for getS!
double <oint44getR() *onst { return +; #

8or&ettin& to add this *onst can #e a source of much frustration #ecause the C++ treats getR() and getR() *onst as two different functions! 0e will discuss why this is later in this chapter! 'n a *onst mem#er function- all the class's instance varia#les are treated as *onst! .ou can read their values- #ut must not modify them! Similarly- inside a *onst mem#er function- you cannot call other non1 *onst mem#er functions! The reason for this is strai&htforward= #ecause non1 *onst mem#er functions can modify the receiver o#*ect- if a *onst mem#er function could invoke a non1 *onst function- then the *onst function mi&ht indirectly modify the receiver o#*ect! 7ut #eyond these restrictions- *onst mem#er functions can do anythin& that re&ular mem#er functions can! Suppose- for e)ample- that we wish to update the <oint class to support a mem#er function called distan*e;o=rigin which returns the distance #etween the receiver o#*ect and the point K0- 0L! 7ecause this function shouldn't modify the receiver o#*ect- we'll mark it *onst- as shown here=

Chapter ;& Ge$ining Abstractions


*lass <oint { $ubli*4 <oint(double +, double %); double getR() *onst; double getS() *onst; void setR(double ne'R); void setS(double ne'S); double distan*e;o=rigin() *onst; $rivate4 double +, %; #;

1 ;A< 1

Bathematically- the distance #etween a point and the ori&in is defined as x 2 y 2 ! Usin& the s[rt function from the *math) header file- we can implement the distan*e;o=rigin function as follows=
void <oint44distan*e;o=rigin() *onst { double d+ = getR(); "" 7egal1 getR is *onst. double d% = %; "" 7egal1 Ieading an instan*e variable. d+ 3= d+; "" 7egal1 2eAre modif%ing d+, 'hi*h isnAt an "" instan*e variable. d% 3= d%; "" 7egal1 6ame reason as above. return s[rt(d+ ! d%); "" 7egal1 s[rt is a free fun*tion that *anAt "" modif% the *urrent ob>e*t. #

+ltho#/h this *#nction is mar0ed *onst, we have s#bstantial leeway with what we can do in the implementation. He can call the getR *#nction, since it too is mar0ed *onst. He can also read the val#e o* % and store it in another variable beca#se this doesn.t chan/e its val#e. +dditionally, we can chan/e the val#es o* the local variables d+ and d%, since doin/ so doesn.t chan/e any o* the receiver obAect.s data members. <emember, *onst member *#nctions /#arantee that the receiver object doesn.t chan/e, not that the *#nction doesn.t chan/e the val#es o* any variables. Jinally, we can call *ree *#nctions, since those *#nctions don.t have access to the class.s data members and there*ore cannot modi*y the receiver. const 4eferences Throu&hout this te)t we've used pass1#y1reference #y default when passin& heavy o#*ects like ve*tors and ma$s as parameters to functions! This improves pro&ram efficiency #y avoidin& e)pensive copy operations! Unfortunately- thou&h- usin& pass1#y1reference in this way makes it more difficult to reason a#out a function's #ehavior! 8or e)ample- suppose you see the followin& function prototype=
void 9o6omething(ve*tor int)? ve*);

.ou know that this function accepts a ve*tor int) #y reference- #ut it's not clear why! 2oes 9o6omething modify the contents of the ve*tor int)- or is it *ust acceptin& #y reference to avoid makin& a deep copy of the ve*tor> 0ithout knowin& which of the two meanin&s of pass1#y1reference the function writer intended- you should #e wary a#out passin& any important data into this function! Gtherwise- you mi&ht end up losin& important data as the function destructively modifies the parameter! 0e are in an interestin& situation! 'f we don't use pass1#y1reference on functions that take lar&e o#*ects as parameters- our pro&rams will pay su#stantial runtime costs unnecessarily! Gn the other hand- if we do pass lar&e o#*ects #y reference- we make it more difficult to reason a#out e)actly what the functions in our

1 ;?0 1

Chapter ;& Ge$ining Abstractions

pro&ram are tryin& to do! 'n other words- we can make a tradeoff #etween e$$iciency and clarity! 'n many cases- this tradeoff is necessary! Clean- strai&htforward al&orithms are often fast and efficient- #ut more often than not they are slower than their more intricate counterparts! 7ut in this particular arena- there is an easy way to &ain the efficiency of pass1#y1reference without the associated am#i&uity= const re$erences! , *onst reference is- in many ways- like a normal reference! *onst references refer to o#*ects and varia#les declared elsewhere in the pro&ram- and any operations performed on the reference are instead performed on the o#*ect #ein& referred to! /owever- unlike re&ular references- *onst references treat the o#*ect they alias as thou&h it were *onst! 'n other words- *onst references capture the notion of loo*ing at an o#*ect without #ein& a#le to modi$y it! To see how *onst references work in practice- let's consider an e)ample! Suppose that we want to write a function which prints out the contents of a ve*tor int)! Such a function clearly should not modify the ve*tor- and so we can prototype this function as follows=
void <rintJe*tor(*onst ve*tor int)? ve*);

"otice that this function takes in a *onst ve*tor int)?! This is a *onst reference Kalso called a re$erence"to"constL! 'nside the <rintJe*tor function- the ve* parameter is treated as thou&h it were *onst- and so we cannot make any chan&es to it! Thus the followin& implementation of <rintJe*tor is perfectly le&al=
void <rintJe*tor(*onst ve*tor int)? ve*) { for (siUeLt B = 0; B ve*.siUe(); !!B) *out ve*[B] endl; #

,lthou&h the <rintJe*tor function takes in a reference to a *onst ve*tor int)- it is perfectly le&al to pass #oth *onst and non1*onst ve*tor int)s to <rintJe*tor! 0hether or not the ori&inal ve*tor is *onst- inside the <rintJe*tor function C++ treats the vector as thou&h it were *onst! Thus it's le&al Kand encoura&edL to write code like this=
void <rintJe*tor(*onst ve*tor int)? ve*) { for (siUeLt B = 0; B ve*.siUe(); !!B) *out ve*[B] endl; # int main() { ve*tor int) m%Je*tor(K@:L(K;6); <rintJe*tor(m%Je*tor); # "" 7egal1 m%Je*tor treated *onst in <rintJe*tor m%Je*tor isnAt *onst out here.

m%Je*tor.$ushLba*B(8CD); "" 7egal1

.ou mi&ht #e a #it uneasy with the idea of passin& a non1 *onst varia#le into a function that takes a reference1to1*onst! ,fter all- somethin& of type ;%$e isn't the same as somethin& of type *onst ;%$e! 0e can't assi&n values to *onst o#*ects- nor can we invoke their non1 *onst mem#er functions! /oweverit is perfectly safe to treat a non1 *onst o#*ect as thou&h it were *onst #ecause the le&al operations on a *onst o#*ect are a subset of the le&al operations on a non1 *onst o#*ect! That is- every o#*ect's pu#lic interface can #e split into two parts- a *onst interface of non1mutatin& operations and a non1 *onst interface of operations which chan&e the o#*ect's state! This is shown #elow=

Chapter ;& Ge$ining Abstractions

1 ;?1 1

Ob6+*t Stat+

Non)const int+r5a*+

const int+r5a*+

'n this picture- the o#*ect's internal state is represented #y the fuzzy cloud- with the *onst and non1*onst interfaces each havin& access to the internals! 0hen an o#*ect is non1 *onst- it has #oth interfacesQ when *onst it has only the *onst interface! Usin& this mental model- let's think a#out what happens when we pass an o#*ect #y reference1to1*onst into a function! 7ecause the called function takes in a reference1to1 *onst- we can treat the function as thou&h it e)pects only the *onst interface for an o#*ect! 3raphically=

Ob6+*t Stat+

const int+r5a*+

Ca--+d F0n*tion

Non)const int+r5a*+

const int+r5a*+

Ca--ing F0n*tion 0hat does this idea mean for you as a pro&rammer> 'n particular- when writin& functions that need to #e a#le to look at data #ut not modify it- you should stron&ly consider usin& pass1#y1reference1to1 *onst! This &ives you the #enefits of pass1#y1reference Khi&her efficiencyL with the added &uarantee that the parameter won't #e destructively modified! Gf course- while it's le&al to pass non1 *onst o#*ects to functions acceptin& *onst references- you cannot pass *onst o#*ects into functions acceptin& non1 *onst references! The reason for this is simple= if an o#*ect is marked *onst- its value cannot #e chan&ed! 'f a *onst o#*ect could #e passed into a function #y non1 *onst reference- that function could modify the ori&inal o#*ect- su#vertin& *onstness! .ou can think of *onst as a universal accepter and of non1 *onst as the universal donor ( you can convert #oth *onst and non1*onst data to *onst data- #ut you can't convert *onst data to non1*onst data! Thinkin& a#out this usin& our two1interface analo&y- if you have access to a class's non1*onst interface- you can always i&nore it and *ust use the *onst interface! /owever- if you only have access to the *onst interface- you can't suddenly &ive yourself access to the non1 *onst interface!

1 ;?; 1

Chapter ;& Ge$ining Abstractions

,lthou&h *onst references #ehave for the most part like re&ular references- there is one particularly important #ehavioral aspect where they diver&e! Suppose we are &iven the followin& prototype for a function called 9o6omething- which takes in a reference to an int=
void 9o6omething(int? +);

Kiven this prototype, each o* the *ollowin/ calls to 9o6omething is ille/alF


9o6omething(8CD); 9o6omething(E.D8FEF); "" 1roblem4 5annot $ass literal b% referen*e "" 1roblem4 5annot $ass literal b% referen*e

double m%9ouble; 9o6omething(m%9ouble); "" 1roblem4 int? *annot bind to double

et's e)amine e)actly why each of these three calls fail! 'n the first case- we tried to pass the inte&er literal into the 9o6omething function! This will cause pro#lems if 9o6omething tries to modify its parameter! Suppose- for e)ample- that 9o6omething is implemented as follows=
void 9o6omething(int? +) { + = 0; #

'f we pass 1@D directly into 9o6omething- the the line + = 0 would try to store the value 0 into the inte&er literal 1@D! This is clearly nonsensical- and so the compiler disallows it! The second erroneous call to 9o6omething Kwhere we pass in ;!D1E;EL fails for the same reason! /owever- what of the third call9o6omething(m%9ouble)> This fails #ecause m%9ouble is a double- not an int- and althou&h it's possi#le to typecast a double to an int the C++ lan&ua&e e)plicitly says that this is not accepta#le! This may seem harsh- #ut it allows C++ pro&rams to run e)tremely efficiently #ecause the compiler can assume that the parameter + is #ound to an actual int- not somethin& implicitly converti#le to an int!P /owever- suppose we chan&e the prototype of 9o6omething to accept its parameter #y *onst referenceas shown here=
void 9o6omething(*onst int? +);

Then all of the followin& calls to 9o6omething are perfectly le&al=


9o6omething(8CD); 9o6omething(E.D8FEF); double m%9ouble; 9o6omething(m%9ouble); "" 7egal "" 7egal "" 7egal1

0hy the difference> Think a#out why all of the a#ove e)amples caused pro#lems when mi)ed with non1 *onst references! 'n the first case- we mi&ht accidentally assi&n a new value to an inte&er literalQ the second case ran into similar pro#lems! 'n the third case- due to hardware restrictions- we cannot #ind an int? to a double #ecause writin& a value to that int? would result in incorrect #ehavior! ,ll of these
P ' know that this e)planation mi&ht seem a #it fuzzy- primarily #ecause the main reason is technical and has to do with how ints and doubles are represented in the machine! 'f you try to e)ecute the machine code instructions to store an inte&er value into a varia#le that's declared as a double- the double will take on a completely meanin&less value that has nothin& to do with the inte&er that we intended to store in it! 'f you're interested in learnin& more a#out why this is- consider takin& a compilers course or studyin& an assem#ly lan&ua&e KB'CS or )E6L! 'f you still don't understand why int?s can't #e #ound to doubles- send me an email and ' can try to e)plain thin&s in more detail!

Chapter ;& Ge$ining Abstractions

1 ;?@ 1

cases have to do with the fact that the reference can #e used to modify the o#*ect it's #ound to! 7ut when workin& with *onst references- none of these pro#lems are possi#le #ecause the referenced value can't #e chan&ed throu&h the reference! 7ecause normal restrictions on references do not apply to *onst references- you can treat pass1#y1 reference1to1*onst as a smarter version of pass1#y1value! ,ny value that could #e passed #y value can #e passed #y reference1to1*onst- #ut when usin& reference1to1*onst o#*ects won't #e copied in most cases! 0e will address this later in this chapter! 8or now- treatin& pass1#y1reference1to1 *onst as a more efficient pass1#y1reference will #e wise! const and !ointers The *onst keyword is useful- #ut has its share of 5uirks! Cerhaps the most persistent source of confusion when workin& with *onst arises when mi)in& *onst and pointers! 8or e)ample- suppose that you want to declare a C strin& as a &lo#al constant! Since to declare a &lo#al C++ string constant you use the synta)
*onst string BGlobal5$$6tring = /;his is a string1/;

.ou mi&ht assume that to make a &lo#al C strin& constant- the synta) would #e=
*onst *har3 BGlobal6tr = /;his is a string1/; "" 1roblem4 7egal but in*orre*t

This synta) is partially correct! 'f you were ever to write BGlobal6tring[0] = ARA- rather than &ettin& se&mentation faults at runtime Ksee the C strin&s chapter for more infoL- you'd instead &et a compiler error that would direct you to the line where you tried to modify the &lo#al constant! 7ut unfortunately this varia#le declaration contains a su#tle #ut crucial mistake! Suppose- for e)ample- that we write the followin& code=
BGlobal6tring = /Ieassigned1/;

/ere- we reassi&n BGlobal6tring to point to the strin& literal 4Feassi&nedR6 "ote that we didn't modify the contents of the character se5uence BGlobal6tring points to ( instead we chan&ed what character se@uence )*lo'al+tring points to! 'n other words- we modified the pointer- not the pointee- and so the a#ove line will compile correctly and other code that references BGlobal6tring will suddenly #e&in usin& the strin& 4Feassi&nedR6 instead of 4This is a strin&R6 as we would hope! C++ distin&uishes #etween two similar1soundin& entities= a pointer"to"const and a const pointer! , pointer1to1*onst is a pointer like BGlobal6tring that points to data that cannot #e modified! 0hile you're free to reassi&n pointers1to1 *onst- you cannot chan&e the value of the elements they point to! To declare a pointer1to1*onst- use the synta) const %ypeG my1ointer- with the *onst on the left of the star! ,lternatively- you can declare pointers1to1*onst #y writin& %ype constG my1ointer. , const pointer- on the other hand- is a pointer that cannot #e assi&ned to point to a different value! Thus with a *onst pointer- you can modify the pointee #ut not the pointer! To declare a *onst pointer- you use the synta) %ypeG const myHonst1ointer- with the *onst on the ri&ht side of the star! /erem%5onst<ointer can't #e reassi&ned- #ut you are free to modify the value it points to! To illustrate #y analo&y- a pointer1to1 *onst is like a telescope ( it can look at other o#*ects- and freely chan&e which o#*ects it looks at- #ut it cannot apply any chan&es to those o#*ects! , *onst pointer- on the other hand- is like an industrial laser! The laser can #e turned on at hi&h power to cut a sheet of metal- or at low power to &et a sense of what the metal looks like- #ut the #eam is always pointed at the same place! .ou wouldn't try to cut a sheet of metal with a telescope- nor would you try to look at an o#*ect at a

1 ;?A 1

Chapter ;& Ge$ining Abstractions

distance #y #lastin& a hi&h1ener&y laser at it! Femem#erin& whether you want a pointer1to1 *onst Klook #ut don't touchL or a *onst pointer Ktouch- #ut only touch one thin&L will #e tricky at first- #ut will #ecome more natural as you mature as a pro&rammer! "ote that the synta) for a pointer1to1 *onst is *onst ;%$e 3 $tr while the synta) for a *onst pointer is ;%$e 3 *onst $tr! The only difference is where the *onst is in relation to the star! Gne trick for remem#erin& which is which is to read the varia#le declaration from ri&ht1to1left! 8or e)ample- readin& *onst ;%$e 3 $tr #ackwards says that 4$tr is a pointer to a ;%$e that's *onst-6 while ;%$e 3 *onst $tr read #ackwards is 4$tr is a *onst pointer to a ;%$e!6 Feturnin& to the C strin& e)ample- to make BGlobal6tring #ehave as a true C strin& constant- we'd need to make the pointer #oth a *onst pointer and a pointer1to1 *onst! This may seem stran&e- #ut is perfectly le&al C++! The result is a *onst pointer1to1*onst- a pointer that can only refer to one o#*ect and that cannot chan&e the value of that o#*ect! Syntactically- this looks as follows=
*onst *har 3 *onst BGlobal6tring = /;his is a string1/;

"ote that there are two *onsts here ( one #efore the star and one after it! /ere- the first *onst indicates that you are declarin& a pointer1to1 *onst- while the second means that the pointer itself is *onst! Usin& the trick of readin& the declaration #ackwards- here we have 4 BGlobal6tring is a *onst pointer to a *har that's *onst!6 This is the correct way to make the C strin& completely *onst- althou&h it is admittedly a #it clunky! The followin& ta#le summarizes what types of pointers you can create with *onst= Declaration 6/nta*
*onst ;%$e3 m%<tr ;%$e *onst3 m%<tr ;%$e3 *onst m%<tr *onst ;%$e3 *onst m%<tr ;%$e *onst3 *onst m%<tr

@ame
Cointer1to1*onst Cointer1to1*onst
*onst pointer

Can reassign:
.es .es @o

Can modif/ +ointee:


@o @o .es @o @o

*onst pointer1to1*onst @o *onst pointer1to1*onst @o

,s with references and references1to1 *onst- it is le&al to set a pointer1to1 *onst to point to a non1*onst o#*ect! This simply means that the o#*ect cannot #e modified throu&h the pointer1to1 *onst! const8iterator Suppose you have a function that accepts a ve*tor string) #y reference1to1*onst and you'd like to print out its contents! .ou mi&ht want to write code that looks like this=
void <rintJe*tor(*onst ve*tor string)? m%Je*tor) { for(ve*tor string)44iterator itr = m%Je*tor.begin(); "" 1roblem itr 1= m%Je*tor.end(); !!itr) *out 3itr endl; #

'nitially- this code seems perfectly fine- #ut unfortunately the compiler will &ive you some positively ferocious errors if you try to compile this code! The pro#lem has to do with a su#tlety involvin& ST iterators and *onst! "otice that in the first part of the for loop we declare an o#*ect of type ve*tor string)44iterator! 7ecause the ve*tor is *onst- somehow the compiler has to know that the

Chapter ;& Ge$ining Abstractions

1 ;?? 1

iterator you're &ettin& to the ve*tor can't modify the ve*tor's contents! Gtherwise- we mi&ht #e a#le to do somethin& like this=
"3 Kote4 ;his *ode doesnAt *om$ile. (t >ust sho's off 'hat ha$$ens if 'e 3 *ould get an iterator to a *onst ve*tor. 3" void Evil&un*tion(*onst ve*tor string)? m%Je*tor) { ve*tor string)44iterator itr = m%Je*tor.begin(); 3itr = GEE "" _ust modified a *onst ob>e*t1 #

'n other words- if we could &et an iterator to iterate over a *onst ve*tor- that iterator could #e used in fiendish and dia#olical ways to modify the contents of the ve*tor- somethin& we promised not to do! This raises an interestin& issue! et's reconsider our Kcurrently flawedL implementation of <rintJe*tor=
void <rintJe*tor(*onst ve*tor string)? m%Je*tor) { for(ve*tor string)44iterator itr = m%Je*tor.begin(); itr 1= m%Je*tor.end(); !!itr) *out 3itr endl; # "" 1roblem

This code doesn't compile #ecause the for loop tries to &et an iterator that traverses the ve*tor! ,s shown a#ove- &iven an iterator over a *onst ve*tor- it's possi#le to modify the contents of that vector and su#vert *onstness! 7ut in this function we don)t modify the contents of the ve*tor ( we're harmlessly traversin& the ve*tor elements and printin& its contentsR So why does the compiler cryptically complain a#out our code> The reason is that constness is conservative! 0hen the C++ compiler checks your code to ensure that you haven't violated the sanctity of *onst- its analysis is imprecise! Father than determinin& whether or not your code actually modifies a *onst varia#le- it checks for syntactic structures which violate *onst ( do you assi&n a a *onst varia#le> 2o you invoke a non1*onst function on a *onst varia#le> 2o you pass a *onst varia#le into a function which takes an ar&ument #y non1*onst reference> 7ecause of this- it is possi#le to write code that cannot possi#ly chan&e the value of a *onst varia#le #ut which is still re*ected #y the compiler! 8or e)ample- consider the followin& code snippet=
void 6ubtle&un*tion(*onst ve*tor string)? m%Je*tor) { if (m%Je*tor.em$t%()) m%Je*tor.*lear(); "" Error1 5alls non-*onst fun*tion. #

This function checks to see if the parameter is the empty vector- and- if so- calls *lear on that vector! Callin& *lear on the empty ve*tor does nothin& to that ve*tor- and so technically speakin& this function never chan&es the value of its parameter! /owever- the C++ compiler will still re*ect this code- #ecause you invoked *lear Ka non&*onst mem#er functionL on a *onst ve*tor! 0hy does the compiler take this approach> The answer is that it is provably impossible to #uild a compiler that can actually determine whether or not a C++ function will chan&e the value of a particular varia#le! .ou read that correctly ( no compiler- no matter how sophisticated or clever- can correctly determine in all cases whether a C++ pro&ram will read or write a particular varia#le! 7ecause of this- C++'s rules for *onstness have a mar&in of error! Some pro&rams that will never chan&e the value of a certain varia#le will cause compiler errors- #ut any pro&ram that correctly o#eys *onst will ensure that *onst varia#les are never overwritten! This e)plains why- in our simple <rintJe*tor e)ample- the compiler complained! ,lthou&h we never actually overwrite the elements of the ve*tor usin& our iterator- the fact that someone with an iterator could overwrite the elements of the ve*tor is enou&h to cause the compiler to panic!

1 ;?6 1

Chapter ;& Ge$ining Abstractions

7ecause raw iterators don't play nicely with *onst containers- we're &oin& to need to chan&e our code! Gne idea you may have had would #e to mark the iterator *onst to prevent it from overwritin& the elements of the ve*tor! 0hile well1intentioned- this approach won't work! , *onst iterator is like a *onst pointer ( it can't chan&e what element it iterates over- #ut it can chan&e the value of the elements it iterates over! This is the reverse of what we want ( we want an iterator that can't chan&e the values it looks at #ut can chan&e which elements it iterates over! 8or this- we can use const%iterators! Jach ST container that defines an iterator also defines a *onstLiterator that can read the values from the container #ut not write them! Usin& a *onstLiterator- we can rewrite our implementation of <rintJe*tor as follows=
void <rintJe*tor(*onst ve*tor string)? m%Je*tor) { for(ve*tor string)44*onstLiterator itr = m%Je*tor.begin(); "" 5orre*t1 itr 1= m%Je*tor.end(); !!itr) *out 3itr endl; #

To maintain *onstness- you cannot use *onstLiterators in functions like insert or erase that modify containers! .ou can- however- define iterator ran&es usin& *onstLiterators for al&orithms like binar%Lsear*h that don't modify the ran&es they apply to! There is one su#tle point we have &lossed over in this discussion ( how does the ve*tor *now that it should hand #ack a *onstLiterator when marked *onst and a re&ular iterator otherwise> That is- how do the ve*tor.s begin and end functions hand #ack o#*ects of two different types #ased on whether or not the ve*tor is *onst> The answer may surprise you! /ere is a Ksli&htly simplifiedL version of the ve*tor interface which showcases the begin and end functions=
tem$late t%$ename ;) *lass ve*tor { $ubli*4 iterator begin(); iterator end(); *onstLiterator begin() *onst; *onstLiterator end() *onst; "3 ... et*. ... 3" #;

"otice that there are two begin functions ( one of which is non1 *onst and returns a re&ular iteratorand one of which is *onst and returns a *onstLiterator! There are similarly two versions end function! This is a techni5ue known as const"overloading and allows a function to have two different #ehaviors #ased on whether or not an o#*ect is *onst! 0hen a *onst1overloaded function is invoked- the version of the function is called that matches the *onstness of the receiver o#*ect! 8or e)ample- if you call begin() on a *onst ve*tor- it will invoke the *onst version of begin() and return a *onstLiterator! 'f begin() is invoked on a non1*onst ve*tor- then the non1*onst version of begin() will #e invoked and the function will yield a re&ular iterator! 0e will see some e)amples of *onst1overloadin& in upcomin& sections! =imitations of const ,lthou&h *onst is a useful pro&rammin& construct- certain aspects of *onst are counterintuitive and can lead to su#tle violations of *onstness! Gne common pro#lem arises when usin& pointers in *onst

Chapter ;& Ge$ining Abstractions

1 ;?D 1

mem#er functions! Suppose you have the followin& implementation of class Je*tor- which acts like a ve*tor int)=
*lass Je*tor { $ubli*4 "3 ... other members ...3" void *onst&un*tion() *onst; $rivate4 int3 elems; #;

Consider the followin& le&al implementation of *onst&un*tion=


Je*tor44*onst&un*tion() *onst { elems[0] = 8CD; #

Unfortunately- while this code modifies the value of the o#*ect pointed to #y elems- it is perfectly le&al C++ code #ecause it doesn't modify the value of elems O instead- it modifies the value of the elements pointed at #y elems! 'n effect- #ecause the mem#er function is declared *onst- elems acts as a const pointer Kthe pointer can't chan&eL instead of a pointer"to"const Kthe pointee can't chan&eL! This raises the issue of the distinction #etween 4#itwise *onstness6 and 4semantic *onstness!6 Iitwise constness- which is the type enforced #y C++- means that *onst o#*ects are prohi#ited from makin& any #itwise chan&es to themselves! 'n the a#ove e)ample- since the value of the elems pointer didn't chan&e- C++ considers the *onst&un*tion implementation *onst1correct! /owever- from the viewpoint of semantic constness*onst classes should #e prohi#ited from modifyin& anythin& that would make the o#*ect appear somehow different! 0ith re&ards to the a#ove scenario with elems- the class isn't semantically *onst #ecause the o#*ect- while *onst- was a#le to modify its data! 0hen workin& with *onst it's important to remem#er that while C++ will enforce #itwise *onstness- you must take care to ensure that your pro&ram is semantically *onst! 8rom your perspective as a pro&rammer- if you invoke a *onst mem#er function on an o#*ect- you would e)pect the receiver to #e unchan&ed! 'f the function isn't semantically *onst- however- this won't #e the case- and a *onst mem#er function mi&ht make si&nificant chan&es to the o#*ect's state! To demonstrate the difference #etween #itwise and semantically *onst code- let's consider another mem#er function of the Je*tor class that simply returns the internally stored strin&=
int3 Je*tor44ra'Elems() *onst { return elems; #

'nitially- this code looks correct! Since returnin& the6tring doesn't modify the receiver o#*ect- the function is #itwise *onst! 7ut this code entirely #ypasses *onstness! Consider- for e)ample- this code=
void <ro*essIa'Elements(*onst Je*tor? v) { int3 elems = v.ra'Elems(); for (siUeLt i = 8; i v.siUe(); !!i) "" 1roblem4 6ubverts *onst1 elems[i Q 8] = elems[i]; #

/ere- we use the pointer o#tained from ra'Elems to indirectly move around the elements of the array! ,lthou&h v is marked *onst in this e)ample- we somehow have chan&ed its contents! This entirely defeats

1 ;?E 1

Chapter ;& Ge$ining Abstractions

the purpose of *onst and should convey why maintainin& semantic *onstness is a crucial part of &ood pro&rammin& practice!

Chapter ;& Ge$ining Abstractions

1 ;?< 1

The a#ove implementation of ra'Elems is fatally flawed and allows clients to su#vert the *onstness of the receiver o#*ect! /ow can we modify ra'Elems so that the a#ove code no lon&er works> Gne particularly ele&ant solution is to modify the si&nature of ra'Elems so that it returns a *onst int3 instead of a raw int3! 8or e)ample=
*onst int3 Je*tor44ra'Elems() *onst { return elems; #

7ecause the returned array has #een marked *onst- clients cannot modify any of the characters in the returned se5uence! ,s a &eneral rule of thum#- avoid returnin& non1 *onst pointers from mem#er functions that are marked *onst! There are e)ceptions to this rule- of course- #ut in most cases *onst functions should return pointers1to1*onst! mutable 7ecause C++ enforces #itwise *onstness rather than semantic *onstness- you mi&ht find yourself in a situation where a mem#er function chan&es an o#*ect's #itwise representation while still #ein& semantically *onst! ,t first this mi&ht seem unusual ( how could we possi#ly leave the o#*ect in the same lo&ical state if we chan&e its #inary representation> ( #ut such situations can arise in practice! 8or e)ample- suppose that we want to write a class that represents a &rocery list! The class definition is provided here=
*lass Gro*er%7ist { $ubli*4 Gro*er%7ist(*onst string? filename); "" 7oad from a file. "3 ... other member fun*tions ... 3" string get(temAt(int inde+) *onst; $rivate4 ve*tor string) data; #;

The Gro*er%7ist constructor takes in a filename representin& a &rocery list Kwith one element per lineLthen allows us to look up items in the list usin& the mem#er function get(temAt! 'nitially- we mi&ht want to implement this class as follows=
Gro*er%7ist44Gro*er%7ist(*onst string? filename) { "3 Iead in the entire *ontents of the file and store in the ve*tor. 3" ifstream in$ut(filename.*Lstr()); data.insert(data.begin(), istreamLiterator string)(in$ut), istreamLiterator string)()); # "3 Ieturns the element at the $osition s$e*ified b% inde+. 3" string Gro*er%7ist44get(temAt(int inde+) *onst { return data[inde+]; #

/ere- the Gro*er%7ist constructor takes in the name of a file and reads the contents of that file into a ve*tor string) called data! The get(temAt mem#er function then accepts an inde) and returns the correspondin& element from the ve*tor! 0hile this implementation works correctly- in many cases it is needlessly inefficient! Consider the case where our &rocery list is several million lines lon& Kmay#e if

1 ;60 1

Chapter ;& Ge$ining Abstractions

we're literally tryin& to find enou&h food to feed an armyL- #ut where we only need to look at the first few elements of the list! 0ith the current implementation of Gro*er%7ist- the Gro*er%7ist constructor will read in the entire &rocery list file- an operation which undou#tedly will take a lon& time to finish and dwarfs the small time necessary to retrieve the stored elements! /ow can we resolve this pro#lem> There are several strate&ies we could use to eliminate this inefficiency! Cerhaps the easiest approach is to have the constructor open the file- and then to only read in data when it's e)plicitly re5uested in the get(temAt function! That way- we don't read any data unless it's a#solutely necessary! /ere is one possi#le implementation=
*lass Gro*er%7ist { $ubli*4 Gro*er%7ist(*onst string? filename); "3 ... other member fun*tions ... 3" string get(temAt(int inde+); "" 1roblem" Ko longer *onst $rivate4 ve*tor string) data; ifstream sour*e6tream; #; Gro*er%7ist44Gro*er%7ist(*onst string? filename) { sour*e6tream.o$en(filename.*Lstr())E "" =$en the file. # string Gro*er%7ist44get(temAt(int inde+) { "3 Iead in enough data to satisf% the re[uest. (f 'eAve alread% read it 3 in, this loo$ 'ill not e+e*ute and 'e 'onAt read an% data. 3" 'hile(inde+ )= data.length()) { string line; getline(sour*e6tream, line); data.$ushLba*B(line); # return data[inde+];

Unlike our previous implementation- the new Gro*er%7ist constructor opens the file without readin& any data! The new get(temAt function is sli&htly more complicated! 7ecause we no lon&er read all the data in the constructor- when asked for an element- one of two cases will #e true! 8irst- we mi&ht have already read in the data for that line- in which case we simply hand #ack the value stored in the data o#*ect! Second- we may need to read more data from the file! 'n this case- we loop readin& data until there are enou&h elements in the data ve*tor to satisfy the re5uest- then return the appropriate strin&! ,lthou&h this new implementation is more efficient- P the get(temAt function can no lon&er #e marked *onst #ecause it modifies #oth the data and sour*e6tream data mem#ers! 'f you'll notice- thou&hdespite the fact that the get(temAt function is not #itwise *onst- it is semantically *onst! Gro*er%7ist is supposed to encapsulate an immuta#le &rocery list- and #y shiftin& the file readin& from the constructor to get(temAt we have only chan&ed the implementation- not the &uarantee that get(temAt will not modify the list! 0e've reached an impasse= the interface for Gro*er%7ist should not depend on its
P The &eneral techni5ue of deferrin& computations until they are a#solutely re5uired is called la8y evaluation and is an e)cellent way to improve pro&ram efficiency!

Chapter ;& Ge$ining Abstractions

1 ;61 1

implementation- and so the get(temAt function should #e marked *onst! /owever- we have *ust produced a perfectly reasona#le implementation of Gro*er%7ist that is not #itwise *onst- meanin& that the interface needs to chan&e to accommodate the implementation! 3iven our two conflictin& needs ( &ood interface desi&n and &ood implementation desi&n ( how can we strike a #alance> 8or situations such as these- where a function is semantically *onst #ut not #itwise *onst- C++ provides the mutable keyword! mutable is an attri#ute that can #e applied to data mem#ers that indicates that those data mem#ers can #e modified inside mem#er functions that are marked *onst! Usin& mutable- we can rewrite the Gro*er%7ist class definition to look like this=
*lass Gro*er%7ist { $ubli*4 Gro*er%7ist(*onst string? filename); "" 7oad from a file. "3 ... other member fun*tions ... 3" string get(temAt(int inde+) *onst; "" Ko' marBed *onst $rivate4 "3 ;hese data members no' mutable. 3" mutable ve*tor string) data; mutable ifstream sour*e6tream; #;

7ecause data and sour*e6tream are #oth mutable- the new implementation of get(temAt can now #e marked *onst- as shown a#ove!
mutable is a special1purpose keyword that should #e used sparin&ly and with caution! Buta#le data mem#ers are e)empt from the type1checkin& rules normally applied to *onst and conse5uently are prone to the same errors as non1*onst varia#les! ,lso- once data mem#ers have #een marked mutable- any

mem#er function can modify them- so #e sure to dou#le1check your code for correctness! Bost importantly- thou&h- do not use mutable to silence compiler warnin&s and errors unless you're a#solutely certain that it's the ri&ht thin& to do! 'f you do- you run the risk of havin& functions marked *onst that are neither #itwise nor semantically *onst- entirely defeatin& the purpose of the *onst keyword! const&Correctness I still sometimes come across programmers who thin* const isn)t worth the trouble EAw, const is a pain to write everywhere,F I)ve heard some complain EI$ I use it in one place, I have to use it all the time And anyway, other people s*ip it, and their programs wor* $ine ,ome o$ the libraries that I use aren)t const"correct either Is const worth it(F 'e could imagine a similar scene, this time at a ri$le range& EAw, this gun)s sa$ety is a pain to set all the time And anyway, some other people don)t use it either, and some o$ them haven)t shot their own $eet o$$ F ,a$ety"incorrect ri$lemen are not long $or this world Aor are const"incorrect programmers, carpenters who don)t have time $or hard"hats, and electricians who don)t have time to identi$y the live wire There is no e4cuse $or ignoring the sa$ety mechanisms provided with a product, and there is particularly no e4cuse $or programmers too la8y to write const"correct code ( /er# Sutter- author of E4ceptional C++ and all1around C++ &uru! NSut<EO

1 ;6; 1

Chapter ;& Ge$ining Abstractions

"ow that you're familiar with the mechanics of *onst- we'll e)plore how to use *onst correctly in real1 world C++ code! 'n the remainder of this section- we will e)plore const"correctness- a system for usin& *onst to indicate the effects of your functions Kor lack thereofL! 8rom this point forward- all of the code in this #ook will #e *onst1correct and you should make a serious effort to *onst1correct your own code! 1.at is const&correctness: ,t a hi&h1level- *onst1correct code is code that clearly indicates which varia#les and functions cannot modify pro&ram state! Bore concretely- *onst1correctness re5uires that *onst #e applied consistently and pervasively! 'n particular- *onst1correct code tends to use *onst as follows= $b%ects are ne;er +assed b/ ;alue! ,ny o#*ect that would #e passed #y value is instead passed #y reference1to1*onst or pointer1to1*onst! (ember functions w.ic. do not c.ange state are marked const. Similarly- a function that is not marked *onst should mutate state somehow! Kariables w.ic. are set but ne;er modified are marked const ,&ain- a varia#le not marked *onst should have its value chan&ed at some point!

et us take some time to e)plore the ramifications of each of these items individually! $b%ects are ne;er +assed b/ ;alue C++ has three parameter1passin& mechanisms ( pass1#y1value- pass1#y1reference- and pass1#y1pointer! The first of these re5uires C++ to make a full copy of the parameter #ein& passed in- while the latter two initialize the parameter #y copyin& a pointer to the o#*ect instead of the full o#*ect! P 0hen passin& primitive types Kint- double- *har3- etc!L as parameters to a function- the cost of a deep copy is usually ne&li&i#le- #ut passin& a heavy o#*ect like a string- ve*tor- or ma$ can at times #e as e)pensive as the #ody of the function usin& the copy! Boreover- when passin& o#*ects #y value to a function- those o#*ects also need to #e cleaned up #y their destructors once that function returns! The cost of passin& an o#*ect #y value is thus at least the cost of a call to the class's copy constructor Kdiscussed in a later chapterL and a call to the destructor- whereas passin& that same o#*ect #y reference or #y pointer simply costs a sin&le pointer copy! To avoid incurrin& the overhead of a full o#*ect deep1copy- you should avoid passin& o#*ects #y value into functions and should instead opt to pass either #y reference or #y pointer! To #e *onst1correct- moreoveryou should consider passin& the o#*ect #y reference1to1 *onst or #y pointer1to1*onst if you don't plan on mutatin& the o#*ect inside the function! 'n fact- you can treat pass1#y1reference1to1 *onst or pass1#y1 pointer1to1*onst as the smarter- faster way of passin& an o#*ect #y value! 0ith #oth pass1#y1value and pass1#y1reference1to1*onst- the caller is &uaranteed that the o#*ect will not chan&e value inside the function call! There is one difference #etween pass1#y1reference1to1 *onst and pass1#y1value- thou&h- and that's when usin& pass1#y1value the function &ets a fresh o#*ect that it is free to destructively modify! 0hen usin& pass1#y1reference1to1*onst- the function cannot mutate the parameter! ,t times this mi&ht #e a #it ve)in&! 8or e)ample- consider the 5onvert;o7o'er5ase function we wrote in the earlier chapter on ST al&orithms=
P Feferences are commonly implemented #ehind1the1scenes in a manner similar to pointers- so passin& an o#*ect #y reference is at least as efficient as passin& an o#*ect #y pointer!

Chapter ;& Ge$ining Abstractions

1 ;6@ 1

1 ;6A 1
string 5onvert;o7o'er5ase(string to5onvert) { transform(to5onvert.begin(), to5onvert.end(), to5onvert.begin(), 44tolo'er); return to5onvert; #

Chapter ;& Ge$ining Abstractions

/ere- if we simply chan&e the parameter from #ein& passed1#y1value to #ein& passed1#y1reference1to1 *onst- the code won't compile #ecause we modify the to5onvert varia#le! 'n situations like these- it is sometimes prefera#le to use pass1#y1value- #ut alternatively we can rewrite the function as follows=
string 5onvert;o7o'er5ase(*onst string? to5onvert) { string result = to5onvert; transform(result.begin(), result.end(), result.begin(), 44tolo'er); return result; #

/ere- we simply create a new varia#le called result- initialize it to the parameter to5onvert- then proceed as in the a#ove function! (ember functions w.ic. do not c.ange state are const 'f you'll recall from our earlier discussion of *onst mem#er functions- when workin& with *onst instances of a class- C++ only allows you to invoke mem#er functions which are e)plicitly marked *onst! "o matter how innocuous a function is- if it isn't e)plicitly marked *onst- you cannot invoke it on a *onst instance of an o#*ect! This means that when desi&nin& classes- you should take &reat care to mark *onst every mem#er function that does not chan&e the state of the o#*ect! 's this a lot of work> ,#solutelyR 2oes it pay off> Gf courseR ,s an e)treme e)ample of why you should always mark nonmutatin& mem#er functions *onst- suppose you try to pass a CS1067HI Je*tor to a function #y reference1to1 *onst! Since the Je*tor is marked as *onst- you can only call Je*tor mem#er functions that themselves are *onst! Unfortunately- none of the Je*tor's mem#er functions are *onst- so you can't call any mem#er functions of a *onst Je*tor! , *onst CS1067HI Je*tor is effectively a di&ital #rick! ,s fun as #ricks are- from a functional standpoint they're pretty much useless- so do make sure to *onstify your mem#er functions! 'f you take care to *onst correct all mem#er functions that don't modify state- then your code will have an additional- stron&er property= mem#er functions which are not marked *onst are &uaranteed to make some sort of chan&e to the receiver's internal state! 8rom an interface perspective this is wonderful ( if you want to call a particular function that isn't marked *onst- you can almost &uarantee that it's &oin& to make some form of modification to the receiver o#*ect! Thus when you're &ettin& accustomed to a new code #ase- you can 5uickly determine what operations on an o#*ect modify that o#*ect and which *ust return some sort of internal state! Kariables w.ic. are set but ne;er c.anged are const Taria#les vary! That's why they're called varia#les! Constants- on the other hand- do not! Semanticallythere is a hu&e difference #etween the sorts of operations you can perform on constants and the operations you can perform on varia#les- and usin& one where you meant to use the other can cause all sorts of de#u&&in& headaches! Usin& *onst- we can make e)plicit the distinction #etween constant values and true varia#les- which can make de#u&&in& and code maintenance much easier! 'f a varia#le is *onstyou cannot inadvertently pass it #y reference or #y pointer to a function which su#tly modifies it- nor can you accidentally overwrite it with = when you meant to check for e5uality with ==! Bany years after

Chapter ;& Ge$ining Abstractions

1 ;6? 1

you've marked a varia#le *onst- pro&rammers tryin& to decipher your code will let out a si&h of relief as they realize that they don't need to watch out for su#tle operations which overwrite or chan&e its value! 0ithout &ettin& carried away- you should try to mark as many local varia#les *onst as possi#le! The additional compile1time safety checks and reada#ility will more than compensate for the e)tra time you spent typin& those e)tra five characters! )*am+le8 C61-NBAF (a+ ,s an e)ample of what *onst1correctness looks like in practice- we'll consider how to take a variant of the CS1067HI :a$ class and modify it so that it is *onst1correct! The initial interface looks like this=
tem$late t%$ename Jalue;%$e) *lass :a$ { $ubli*4 :a$(int siUe0int = 808); c:a$(); int siUe(); bool isEm$t%(); void $ut(string Be%, Jalue;%$e value); void remove(string Be%); bool *ontainsWe%(string Be%); "3 get *auses an Error if the Be% does not e+ist. o$erator[] (the 3 fun*tion 'hi*h is *alled 'hen %ou use the ma$[/Be%/] s%nta+) *reates 3 an element 'ith the s$e*ified Be% if the Be% does not alread% e+ist. 3" Jalue;%$e get(string Be%); Jalue;%$e? o$erator[](string Be%); void *lear(); void ma$All(void fn(string Be%, Jalue;%$e val)); tem$late t%$ename 5lient9ata;%$e) void ma$All(void fn(string Be%, Jalue;%$e val, 5lient9ata;%$e? data), 5lient9ata;%$e? data); (terator iterator(); $rivate4 "3 ... (m$lementation s$e*ifi* ... 3" #;

The o$erator[] function shown here is what's called an overloaded operator and is the function that lets us write code to the effect of m%:a$[/We%/] = value and value = m%:a$[/We%/]! 0e will cover overloaded operators in a later chapter- #ut for now you can think of it simply as a function that is called whenever the :a$ has the element1selection #rackets applied to it! The first set of chan&es we should make to the :a$ is to mark all of the pu#lic mem#er functions which don't modify state *onst! This results in the followin& interface=

1 ;66 1

Chapter ;& Ge$ining Abstractions

"3 Kote4 6till more *hanges to maBe. 9o not use this *ode as a referen*e1 3" tem$late t%$ename Jalue;%$e) *lass :a$ { $ubli*4 :a$(int siUe0int = 808); c:a$(); int siUe() *onst; bool isEm$t%() *onst; void $ut(string Be%, Jalue;%$e value); void remove(string Be%); bool *ontainsWe%(string Be%) *onst; "3 get *auses an Error if the Be% does not e+ist. o$erator[] (the 3 fun*tion 'hi*h is *alled 'hen %ou use the ma$[/Be%/] s%nta+) *reates 3 an element 'ith the s$e*ified Be% if the Be% does not alread% e+ist. 3" Jalue;%$e get(string Be%) *onst; Jalue;%$e? o$erator[](string Be%); void *lear(); void ma$All(void fn(string Be%, Jalue;%$e val)) *onst; tem$late t%$ename 5lient9ata;%$e) void ma$All(void fn(string Be%, Jalue;%$e val, 5lient9ata;%$e? data), 5lient9ata;%$e? data) *onst; (terator iterator() *onst; $rivate4 "3 ... (m$lementation s$e*ifi* ... 3" #;

The siUe- isEm$t%- and *ontainsWe% functions are all *onst #ecause they simply 5uery o#*ect properties without chan&in& the :a$! get is also *onst since accessin& a keyHvalue pair in the :a$ does not actually modify the underlyin& state- #ut o$erator[] should definitely not #e marked *onst #ecause it may update the container if the specified key does not e)ist! The trickier functions to *onst1correct are ma$All and iterator! Unlike the ST iterators- CS1067HI iterators are read1only and can't modify the underlyin& container! /andin& #ack an iterator to the :a$ contents therefore cannot chan&e the :a$'s contents- so we have marked iterator *onst! 'n additionsince ma$All passes its ar&uments to the call#ack function #y value- there is no way for the call#ack function to modify the underlyin& container! 't should therefore #e marked *onst! "ow that the interface has its mem#er functions *onst1ified- we should make a second pass over the :a$ and replace all instances of pass1#y1value with pass1#y1reference1to1 *onst! 'n &eneral- o#*ects should never #e passed #y value and should always #e passed either #y pointer or reference with the appropriate *onstness! This eliminates unnecessary copyin& and can make pro&rams perform asymptotically #etter! The resultin& class looks like this=

Chapter ;& Ge$ining Abstractions

1 ;6D 1

"3 Kote4 6till more *hanges to maBe. 9o not use this *ode as a referen*e1 3" tem$late t%$ename Jalue;%$e) *lass :a$ { $ubli*4 :a$(int siUe0int = 808); c:a$(); int siUe() *onst; bool isEm$t%() *onst; void $ut(*onst string? Be%, *onst Jalue;%$e? value); void remove(*onst string? Be%); bool *ontainsWe%(*onst string? Be%) *onst; "3 get *auses an Error if the Be% does not e+ist. o$erator[] (the 3 fun*tion 'hi*h is *alled 'hen %ou use the ma$[/Be%/] s%nta+) *reates 3 an element 'ith the s$e*ified Be% if the Be% does not alread% e+ist. 3" Jalue;%$e get(*onst string? Be%) *onst; Jalue;%$e? o$erator[](*onst string? Be%); void *lear(); void ma$All(void (fn)(*onst string? Be%, *onst Jalue;%$e? val)) *onst; tem$late t%$ename 5lient9ata;%$e) void ma$All(void (fn)(*onst string? Be%, *onst Jalue;%$e? val, 5lient9ata;%$e? data), 5lient9ata;%$e ?data) *onst; (terator iterator() *onst; $rivate4 "3 ... (m$lementation s$e*ifi* ... 3" #;

The parameters to $ut- remove- *ontainsWe%- get- and o$erator[] have all #een updated to use pass1 #y1reference1to1*onst instead of pass1#y1value! The trickier functions to modify are the ma$All functions! These functions themselves accept function pointers which initially took their values #y value! 0e have updated them appropriately so that the function pointers accept their ar&uments #y reference1to1 *onst- since we assume that the class client will also #e *onst1correct! "ote that we did not mark the 5lient9ata;%$e? parameter to ma$All *onst- since the Bap client may actually want to modify that parameter! There is one last chan&e to make- and it concerns the get function- which currently returns a copy of the value associated with a &iven key! ,t a hi&h1level- there is nothin& intuitively wron& with returnin& a copy of the stored value- #ut from an efficiency standpoint we may end up payin& a steep runtime cost #y returnin& the o#*ect #y value! ,fter all- this re5uires a full o#*ect deep copy- plus a call to the o#*ect's destructor once the returned o#*ect &oes out of scope! 'nstead- we'll modify the interface such that this function returns the o#*ect #y reference1to1 *onst! This allows the Bap client to look at the value and- if they choose- copy it- #ut prevents clients from intrusively modifyin& the Bap internals throu&h a *onst function! The final- correct interface for :a$ looks like this=

1 ;6E 1
"3 *onst-*orre*ted version of the 5680NP"R :a$. 3" tem$late t%$ename Jalue;%$e) *lass :a$ { $ubli*4 :a$(int siUe0int = 808); c:a$(); int siUe() *onst; bool isEm$t%() *onst;

Chapter ;& Ge$ining Abstractions

void $ut(*onst string? Be%, *onst Jalue;%$e? value); void remove(*onst string? Be%); bool *ontainsWe%(*onst string? Be%) *onst; "3 get *auses an Error if the Be% does not e+ist. o$erator[] (the 3 fun*tion 'hi*h is *alled 'hen %ou use the ma$[/Be%/] s%nta+) *reates 3 an element 'ith the s$e*ified Be% if the Be% does not alread% e+ist. 3" *onst Jalue;%$e? get(*onst string? Be%) *onst; Jalue;%$e? o$erator[](*onst string? Be%); void *lear(); void ma$All(void (fn)(*onst string? Be%, *onst Jalue;%$e? val)) *onst; tem$late t%$ename 5lient9ata;%$e) void ma$All(void (fn)(*onst string? Be%, *onst Jalue;%$e? val, 5lient9ata;%$e? data), 5lient9ata;%$e ?data) *onst; (terator iterator() *onst; $rivate4 "3 ... (m$lementation s$e*ifi* ... 3" #;

,s an interestin& intellectual e)ercise- compare this code to the ori&inal version of the :a$! The interface declaration is considera#ly lon&er than #efore #ecause of the additional *onsts- #ut ultimately is more pleasin&! Someone unfamiliar with the interface can understand- for e)ample- that the :a$'s (terator type cannot modify the underlyin& container Ksince otherwise the iterator() function wouldn't #e *onstL- and can also note that ma$All allows only a read1only map operation over the :a$! This makes the code more self1documentin&- a &reat #oon to pro&rammers responsi#le for maintainin& this code #ase in the lon& run! 1./ be const&correct: ,s you can see from the e)ample with the CS1067HI :a$- makin& code *onst1correct can #e tricky and time1consumin&! 'ndeed- typin& out all the re5uisite *onsts and ?s can #ecome tedious after a while! So why should you want to #e *onst1correct in the first place> There are multiple reasons why code is #etter off *onst1correct than non1*onst1correct! /ere are a few= Code correctness! 'f nothin& else- markin& code *onst whenever possi#le reduces the possi#ility for lurkin& #u&s in your code! 7ecause the compiler can check which re&ions of the code are and are not muta#le- your code is less likely to contain lo&ic errors stemmin& either from a misuse of an interface or from a #u&&y implementation of a mem#er function!

Chapter ;& Ge$ining Abstractions

1 ;6< 1

Code documentation! *onst1correct code is self1documentin& and clearly indicates to other pro&rammers what it is and is not capa#le of doin&! 'f you are presented an interface for an entirely forei&n class- you may still #e a#le to fi&ure out which methods are safe to call with important data #y notin& which mem#er functions are *onst or accept parameters #y reference1 to1*onst! =ibrar/ integration! The C++ standard li#raries and most third1party li#raries are fully *onst1 correct and e)pect that any classes or functions that interface with them to #e *onst1correct as well! 0ritin& code that is not *onst1correct can prevent you from fully harnessin& the full power of some of these li#raries!

$+timi5ing Construction wit. (ember Initiali5er =ists 0e've *ust concluded a whirlwind tour of *onst- and now it's time to chan&e &ears and talk a#out an entirely different aspect of class desi&n= the mem#er initializer list! "ormally- when you create a class- you'll initialize all of its data mem#ers in the #ody constructor! /owever- in some cases you'll need to initialize instance varia#les #efore the constructor #e&ins runnin&! Cerhaps you'll have a *onst instance varia#le that you cannot assi&n a value- or may#e you have an o#*ect as an instance varia#le where you do not want to use the default constructor! 8or situations like these- C+ + has a construct called the member initiali8er list that you can use to fine1tune the way your data mem#ers are set up! This section discusses initializer list synta)- situations where initializer lists are appropriate- and some of the su#tleties of initializer lists! 3ow C99 Constructs $b%ects To fully understand why initializer lists e)ist in the first place- you'll need to understand the way that C++ creates and initializes new o#*ects! et's suppose you have the followin& class=
*lass 6im$le5lass { $ubli*4 6im$le5lass(); $rivate4 int m%(nt; string m%6tring; ve*tor int) m%Je*tor; #;

et's define the 6im$le5lass constructor as follows=


6im$le5lass446im$le5lass() { m%(nt = H; m%6tring = /5!!1/; m%Je*tor.resiUe(80); #

0hat happens when you create a new instance of the class :%5lass> 't turns out that the simple line of code :%5lass m* actually causes a cascade of events that &oes on #ehind the scenes! et's take a look at what happens- step1#y1step!

1 ;D0 1

Chapter ;& Ge$ining Abstractions

The first step in constructin& a C++ o#*ect is simply to &et enou&h space to hold all of the o#*ect's data mem#ers! The memory is not initialized to any particular value- so initially all of your o#*ect's data mem#ers hold &ar#a&e values! 'n memory- this looks somethin& like this=

int myInt string myItring

!!! Jength" !!! %e5t" !!! Ii6e" !!! Elements" !!!

#ector2int: myKector

,s you can see- none of the instance varia#les have #een initialized- so they all contain *unk! ,t this pointC++ calls the default constructor of each instance varia#le! 8or primitive types- this leaves the varia#les unchan&ed! ,fter this step- our o#*ect looks somethin& like this=

int myInt string myItring

!!! Jength" 0 %e5t" FF Ii6e" 0 Elements" LM

#ector2int: myKector

8inally- C++ will invoke the o#*ect's constructor so you can perform any additional initialization code! Usin& the constructor defined a#ove- the final version of the new o#*ect will look like this=

int myInt string myItring

13 Jength" ) %e5t" FHDDF Ii6e" 10 Elements" L00 00 ... 0 0M

#ector2int: myKector

Chapter ;& Ge$ining Abstractions ,t this point- our o#*ect is fully1constructed and ready to use!

1 ;D1 1

/owever- there's one thin& to consider here! 7efore we reached the 6im$le5lass constructor- C++ called the default constructor on #oth m%6tring and m%Je*tor! m%6tring was therefore initialized to the empty strin&- and m%Je*tor was constructed to hold no elements! /owever- in the 6im$le5lass constructor- we immediately assi&ned m%6tring to hold 4C++R6 and resized m%Je*tor to hold ten elements! This means that we effectively initialized m%6tring and m%Je*tor twice ( once with their default constructors and once in the 6im$le5lass constructor!P To improve efficiency and resolve certain other pro#lems which we'll e)plore later- C++ has a feature called an initiali8er list! ,n initializer list is simply a series of values that C++ will use instead of the default values to initialize instance varia#les! 8or e)ample- in the a#ove e)ample- you can use an initializer list to specify that the varia#le m%6tring should #e set to 4C++R6 #efore the constructor even #e&ins runnin&! To use an initializer list- you add a colon after the constructor and then list which values to initialize which varia#les with! 8or e)ample- here's a modified version of the 6im$le5lass constructor that initializes all the instance varia#les in an initializer list instead of in the constructor=
6im$le5lass446im$le5lass() 4 m%(nt(H), m%6tring(/5!!1/), m%Je*tor(80) { "" Kote4 Em$t% *onstru*tor #

/ere- we're tellin& C++ to initialize the varia#les m%(nt and m%6tring to ? and 4C++R-6 respectively- #efore the class constructor is even called! ,lso- #y writin& m%Je*tor(80)- we're tellin& C++ to invoke the parametrized constructor of m%Je*tor passin& in the value 10- which creates a ve*tor with ten elements! This time- when we create a new o#*ect of type m%Je*tor- the creation steps will look like this= 8irst- as in the previous case- the o#*ect is allocated somewhere in memory and all varia#les have &ar#a&e values=

int myInt string myItring

!!! Jength" !!! %e5t" !!! Ii6e" !!! Elements" !!!

#ector2int: myKector

"e)t- C++ invokes all of the constructors for the o#*ect's data mem#ers usin& the values specified in the initializer list! The o#*ect now looks like this=

P Technically speakin&- the o#*ects are only initialized once- #ut the runtime efficiency is as thou&h the o#*ects were initialized multiple times! 0e'll talk a#out the differences #etween initialization and assi&nment in a later chapter!

1 ;D; 1

Chapter ;& Ge$ining Abstractions

int myInt string myItring

13 Jength" ) %e5t" FHDDF Ii6e" 10 Elements" L00 00 ... 0 0M

#ector2int: myKector

8inally- C++ invokes the :%5lass constructor- which does nothin&! The final version of the class thus is identical to the a#ove version! ,s you can see- the values of the instance varia#les m%(nt- m%6tring- and m%Je*tor are correctly set #efore the 6im$le5lass constructor is invoked! This is considera#ly more efficient than the previous version and will run much faster! "ote that while in this e)ample we used initializer lists to initialize all of the o#*ect's instance varia#lesthere is no re5uirement that you do so! /owever- in practice it's usually a &ood idea to set up all varia#les in an initializer list to make clear what values you want for each of your data mem#ers! !arameters in Initiali5er =ists 'n the a#ove e)ample- the initializer list we used specified constant values for each of the data mem#ers! /owever- it's #oth le&al and useful to initialize data mem#ers with e)pressions instead of literal constants! 8or e)ample- consider the followin& class- which encapsulates a rational num#er=
*lass IationalKumber { $ubli*4 IationalKumber(int numerator = 0, int denominator = 8); "3 ... 3" $rivate4 int numerator, denominator; #;

The followin& is a perfectly le&al constructor that initializes the data mem#ers to the values specified as parameters to the function=
IationalKumber44IationalKumber(int numerator, int denominator) 4 numerator(numerator), denominator(denominator) { "" Em$t% *onstru*tor #

C++ is smart enou&h to realize that the synta) numerator(numerator) means to initialize the numerator data mem#er to the value held #y the numerator parameter- rather than causin& a compile1time error or

Chapter ;& Ge$ining Abstractions

1 ;D@ 1

initializin& the numerator data mem#er to itself! Code of this form mi&ht indicate that you need to rename the parameters to the constructor- #ut is perfectly le&al! Gn an unrelated note- notice that in the IationalKumber class declaration we specified that the numerator and denominator parameters to IationalKumber were e5ual to zero and one- respectively! These are default ar&uments to the constructor and allow us to call the constructor with fewer than two parameters! 'f we don't specify the parameters- C++ will use these values instead! 8or e)ample=
IationalKumber five0alves(H, E); IationalKumber three(C); "" 5alls *onstru*tor 'ith arguments (C, 8) IationalKumber Uero; "" 5alls *onstru*tor 'ith arguments (0, 8)

.ou can use default ar&uments in any function- provided that if a sin&le parameter has a default ar&ument every parameter after it also has a default! Thus the followin& code is ille&al=
void 9o6omething(int + = H, int %); "" 1roblem4 % needs a default

0hile the followin& is le&al=


void 9o6omething(int +, int % = H); "" 7egal

0hen writin& functions that take default ar&uments- you should only specify the default ar&uments in the function prototype- not the function definition! 'f you don't prototype the function- however- you should specify the defaults in the definition! C++ is very strict a#out this and even if you specify the same defaults in #oth the prototype and definition the compiler will complain! 1.en Initiali5er =ists are (andator/ 'nitializer lists are useful from an efficiency standpoint! /owever- there are times where initializer lists are the only syntactically le&al way to set up your instance varia#les! Suppose we'd like to make an o#*ect called 5ounter that supports two functions- in*rement and de*rement- that ad*ust an internal counter! /owever- we'd like to add the restriction that the 5ounter can't drop #elow 0 or e)ceed a user1defined limit! Thus we'll use a parametrized constructor that accepts an int representin& the ma)imum value for the 5ounter and stores it as an instance varia#le! Since the value of the upper limit will never chan&e- we'll mark it *onst so that we can't accidentally modify it in our code! The class definition for 5ounter thus looks somethin& like this=
*lass 5ounter { $ubli*4 5ounter(int ma+Jalue); void in*rement(); void de*rement(); int getJalue() *onst; $rivate4 int value; *onst int ma+imum; #;

Then we'd li*e the constructor to look like this=

1 ;DA 1

Chapter ;& Ge$ining Abstractions

5ounter445ounter(int ma+Jalue) { value = 0; ma+imum = ma+Jalue; "" 1roblem4 2riting to a *onst value1 #

Unfortunately- the a#ove code isn't valid #ecause in the second line we're assi&nin& a value to a varia#le marked *onst! Jven thou&h we're in the constructor- we still cannot violate the sanctity of *onstness! To fi) this- we'll initialize the value of ma+imum in the initializer list- so that ma+imum will #e initiali8ed to the value of ma+Jalue- rather than assigned the value ma+Jalue! This is a su#tle distinction- so make sure to think a#out it #efore proceedin&! The correct version of the constructor is thus
5ounter445ounter(int ma+Jalue) 4 value(0), ma+imum(ma+Jalue) { "" Em$t% *onstru*tor #

"ote that we initialized ma+imum #ased on the constructor parameter ma+Jalue! 'nterestin&ly- if we had for&otten to initialize ma+imum in the initializer list- the compiler would have reported an error! 'n C++- it is mandatory to initialize all *onst primitive1type instance varia#les in an initializer list! Gtherwise- you'd have constants whose values were total &ar#a&e! ,nother case where initializer lists are mandatory arises when a class contains o#*ects with no le&al or meanin&ful default constructor! Suppose- for e)ample- that you have an o#*ect that stores a CS1067HI 6et of a custom type *ustom; with comparison call#ack :%5allba*B! Since the 6et re5uires you to specify the call#ack function in the constructor- and since you're always &oin& to use :%5allba*B as that parameter- you mi&ht think that the synta) looks like this=
*lass 6et2ra$$er5lass { $ubli*4 6et2ra$$er5lass(); $rivate4 6et *ustom;) m%6et(:%5allba*B); "" 1roblem4 Keed a *om$arison fun*tion #;

Unfortunately- this isn't le&al C++ synta)! /owever- you can fi) this #y rewritin& the class as
*lass 6et2ra$$er5lass { $ubli*4 6et2ra$$er5lass(); $rivate4 6et *ustom;) m%6et; "" Kote4 no $arameters s$e*ified #;

,nd then initializin& m%6et in the initializer list as


6et2ra$$er5lass446et2ra$$er5lass() 4 m%6et(:%5allba*B) { "" Set another em$t% *onstru*tor1 #

"ow- when the o#*ect is created- m%6et will have :%5allba*B passed to its constructor and everythin& will work out correctly!

Chapter ;& Ge$ining Abstractions (ulti+le Constructors

1 ;D? 1

'f you write a class with multiple constructors Kwhich- after we discuss of copy constructors- will #e most of your classesL- you'll need to make initializer lists for each of your constructors! That is- an initializer list for one constructor won't invoke if a different constructor is called! 6.aring Information 1it. static Suppose that we're developin& a windowed operatin& system and want to write the code that draws windows on the screen! 0e decide to create a class 2indo' that e)ports a dra'2indo' function! 'n order to display the window correctly- dra'2indo' needs access to a <alette o#*ect that performs primitive renderin& operations like drawin& lines- arcs- and filled poly&ons! ,ssume that we know that the window will always #e drawn with the same <alette! 3iven this description- we mi&ht initially desi&n 2indo' so that it has a <alette as a data mem#er- as shown here=
*lass 2indo' { $ubli*4 "3 ... *onstru*tors, destru*tors, et*. ...3" "3 All 'indo's *an dra' themselves. 3" void dra'2indo'(); $rivate4 "3 ... other data members ... 3" <alette $al; #;

"ow- every window has its own palette and can draw itself appropriately! There's nothin& fundamentally wron& with this setup- #ut it contains a small flaw! et's suppose that we have three different window o#*ects! 'n memory- those o#*ects would look like this= Fir&t In&tan*+ S+*ond In&tan*+ T1ird In&tan*+

Ot1+r 2indo' Data M+mb+r&

Ot1+r 2indo' Data M+mb+r&

Ot1+r 2indo' Data M+mb+r&

1alette pal

1alette pal

1alette pal

Since $al is a data mem#er of 2indo'- every 2indo' has its own <alette! There mi&ht #e an ar#itrary num#er of windows on screen at any time- #ut there's only one screen and it doesn't make sense for every window to have its own palette! ,fter all- each window is likely to use a similar set of colors as those used #y every other window- and it seems more reasona#le for every window to share a sin&le palette- as shown here=

1 ;D6 1 Fir&t In&tan*+ S+*ond In&tan*+

Chapter ;& Ge$ining Abstractions T1ird In&tan*+

Ot1+r 2indo' Data M+mb+r&

Ot1+r 2indo' Data M+mb+r&

Ot1+r 2indo' Data M+mb+r&

1alette pal /ow can we model this in code> Usin& the techni5ues so far- we have few options! 8irst- we could create a &lo#al <alette o#*ect- then have each 2indo' use this &lo#al <alette! This is a particularly #ad choice for two reasons= It uses global ;ariables! 'ndependently of any other stren&ths and weaknesses of this approach&lo#al varia#les are a #i& pro&rammin& no1no! 3lo#als can #e accessed and modified anywhere in the pro&ram- makin& de#u&&in& difficult should pro#lems arise! 't is also possi#le to inadvertently reference &lo#al varia#les inside of unrelated functions- leadin& to su#tle #u&s that can take down the entire pro&ram! It lacks enca+sulation! 7ecause the <alette is a &lo#al varia#le- other parts of the pro&ram can modify the 2indo' <alette without &oin& throu&h the 2indo' class! This leads to the same sorts of pro#lems possi#le with pu#lic data mem#ers= class invariants #reakin& une)pectedly- code written with one version of 2indo' #reakin& when the 2indo' is updated- etc!

Second- we could have each 2indo' o#*ect contain a pointer to a <alette o#*ect- then pass a shared <alette as a parameter to each instance of 2indo'! 8or e)ample- we could desi&n the class like this=
*lass 2indo' { $ubli*4 2indo'(<alette3 $, "3 ... 3"); "3 ... other *onstru*tors, destru*tors, et*. ...3" "3 All 'indo's *an dra' themselves. 3" void dra'2indo'(); $rivate4 "3 ... other data members ... 3" <alette3 $al; #;

This allows us to share a sin&le <alette across multiple 2indo's and looks remarka#ly like the a#ove dia&ram! /owever- this approach has its weaknesses=

Chapter ;& Ge$ining Abstractions

1 ;DD 1

It com+licates $indow creation! et's think a#out how we would &o a#out creatin& 2indo's with this setup! 7efore creatin& our first 2indo'- we'd need to create a <alette to associate with it- as shown here=
<alette3 $ = ne' <alette; 2indo'3 ' = ne' 2indo'($, "3 ... 3");

'f later we want to create more 2indo's- we'd need to keep track of the ori&inal <alette we used so that we can provide it as a parameter to the 2indo' constructor! This means that any part of the pro&ram responsi#le for 2indo' mana&ement needs to know a#out the shared <alette! It ;iolates enca+sulation! Clients of 2indo' shouldn't have to know how 2indo's are implemented- and #y re5uirin& 2indo' users to e)plicitly mana&e the shared <alette we're e)posin& too much detail a#out the 2indo' class! This approach also locks us in to a fi)ed implementation! 8or e)ample- what if we want to switch from <alette to a ;urbo<alette that draws twice as 5uickly> 0ith the current approach all 2indo' clients would need to up&rade their code to match the new implementation! It com+licates resource management ! 0ho is responsi#le for cleanin& up the 2indo' <alette at the end of the pro&ram> 2indo' clients shouldn't have to- since the <alette really #elon&s to the 2indo' class! 7ut no particular 2indo' owns the <alette- since each instance of 2indo' shares a sin&le <alette! There are systems we could use to make cleanup work correctly Ksee the later e)tended e)ample on smart pointers for one possi#ilityL- #ut they increase pro&ram comple)ity!

7oth of these approaches have their individual stren&ths- #ut have draw#acks that outwei&h their #enefits! et's review e)actly what we're tryin& to do! 0e'd like to have a sin&le <alette that's shared across multiple different 2indo's! Boreover- we'd like this <alette to o#ey all of the rules normally applica#le to class desi&n= it should #e encapsulated and it should #e mana&ed #y the class rather than clients! Usin& the techni5ues we've covered so far it is difficult to construct a solution with these properties! 8or a clean solution- we'll need to introduce a new lan&ua&e feature= static data members! 6tatic Data (embers Static data mem#ers are data mem#ers associated with a class as a whole rather than a particular instance of that class! 'n the a#ove e)ample with 2indo' and <alette- the window <alette is associated with ,indo-s in general rather than any one specific 2indo' o#*ect and is an ideal candidate for a static data mem#er! 'n many ways static data mem#ers #ehave similarly to re&ular data mem#ers! 8or e)ample- if a class has a private static data mem#er- only mem#er functions of the class can access that varia#le! /owever- static data mem#ers #ehave differently from other data mem#ers #ecause there is only one copy of each static data mem#er! Jach instance of a class containin& a static data mem#er shares the same version of that data mem#er! That is- if a sin&le class instance chan&es a static data mem#er- the chan&e affects all instances of that class! The synta) for declarin& static data mem#ers is sli&htly more complicated than for declarin& nonstatic data mem#ers! There are two steps= declaration and de$inition! 8or e)ample- if we want to create a static <alette o#*ect inside of 2indo'- we could declare the varia#le as shown here=

1 ;DE 1
*lass 2indo' { $ubli*4 "3 ... *onstru*tors, destru*tors, et*. ...3" "3 All 'indo's *an dra' themselves. 3" void dra'2indo'(); $rivate4 "3 ... other data members ... 3" stati* <alette shared<al; #;

Chapter ;& Ge$ining Abstractions

/ere- shared<al is declared as a static data mem#er usin& the stati* keyword! 7ut while we've declared shared<al as a static data mem#er- we haven't de$ined shared<al yet! Buch in the same way that functions are separated into prototypes KdeclarationsL and implementations KdefinitionsL- static data mem#ers have to #e #oth declared inside the class in which they reside and defined inside the !cpp file associated with that class! 8or the a#ove e)ample- inside the !cpp file for the 2indo' class- we would write
<alette 2indo'44shared<alE

There are two important points to note here! 8irst- when definin& the stati* varia#le- we must use the fully15ualified name K2indo'44shared<alL instead of *ust its local name K shared<alL! Second- we do not repeat the stati* keyword durin& the varia#le declaration ( otherwise- the compiler will think we're doin& somethin& completely different Ksee the 4Bore to J)plore6 sectionL! .ou may have noticed that even thou&h 2indo'44shared<al is private we're still allowed to use it outside the class! This is only le&al durin& definition- and outside of this one conte)t it is ille&al to use 2indo'44shared<al outside of the 2indo' class! 'n some circumstances you may want to create a class containin& a static data mem#er where the data mem#er needs to take on an initial value! 8or e)ample- if we want to create a class containin& an int as a static data mem#er- we would pro#a#ly want to initialize the int to a particular value! 3iven the followin& class declaration=
*lass :%5lass { $ubli*4 void do6omething(); $rivate4 stati* int m%6tati*9ata; #;

't is perfectly le&al to initialize m%6tati*9ata as follows=


int :%5lass44m%6tati*9ata = 8CD;

,s you'd e)pect- this means that m%6tati*9ata initially holds the value 1@D! ,lthou&h the synta) for creatin& a static data mem#er can #e intimidatin&- once initialized static data mem#ers look *ust like re&ular data mem#ers! 8or e)ample- consider the followin& mem#er function=

Chapter ;& Ge$ining Abstractions


void :%5lass44do6omething() { !!m%6tati*9ata; "" :odifies m%6tati*9ata for all *lasses #

1 ;D< 1

"othin& here seems all that out1of1the1ordinary and this code will work *ust fine! "ote- however- that modifications to m%6tati*9ata are visi#le to all other instances of :%5lass! et's consider another e)ample where static data mem#ers can #e useful! Suppose that you're de#u&&in& the windowin& code from #efore and you're pretty sure that you've for&otten to delete all instances of 2indo' that you've allocated with ne'! Since C++ won't &ive you any warnin&s a#out this- you'll need to do the instance countin& yourself! The num#er of active instances of a class is class1specific information that doesn't pertain to any specific instance of the o#*ect- and this is the perfect spot to use static data mem#ers! To handle our instance countin&- we'll modify the 2indo' definition as follows=
*lass 2indo' { $ubli*4 "3 ... *onstru*tors, destru*tors, et*. ...3" void dra'2indo'(); $rivate4 "3 ... other data members ... 3" stati* <alette shared<al; stati* int num(nstan*es; #;

0e'll also define the varia#le outside the class as


int 2indo'44num(nstan*es = 0;

0e know that whenever we create a new instance of a class- the class's constructor will #e called! This means that if we increment num(nstan*es inside the 2indo' constructor- we'll correctly track the num#er of times the a 2indo' has #een created! Thus- we'll rewrite the 2indo' constructor as follows=
2indo'442indo'("3 ... 3") { "3 ... All older initialiUation *ode ... 3" !!num(nstan*es; #

Similarly- we'll decrement num(nstan*es in the 2indo' destructor! 0e'll also have the destructor print out a messa&e if this is the last remainin& instance so we can see how many instances are left=
2indo'44c2indo'() { "3 ... All older *leanu$ *ode ... 3" --num(nstan*es; if(num(nstan*es == 0) *out /Ko more 2indo's13/ endl; #

6tatic (ember 2unctions 'nside of mem#er functions- a special varia#le called this acts as a pointer to the current o#*ect! 0henever you access a class's instance varia#les inside a mem#er function- you're really accessin& the instance varia#les of the this pointer! 8or e)ample- &iven the followin& <oint class=
P This is not meant as a sli&ht to Bicrosoft!

1 ;E0 1
*lass <oint { $ubli*4 <oint(int +7o*, int %7o*); int getR() *onst; int getS() *onst; $rivate4 int +, %; #;

Chapter ;& Ge$ining Abstractions

'f we implement the <oint constructor as follows=


<oint44<oint(int +7o*, int %7o*) { + = +7o*; % = %7o*; #

This code is e5uivalent to


<oint44<oint(int +7o*, int %7o*) { this-)+ = +7o*; this-)% = %7o*; #

/ow does C++ know what value this refers to> The answer is su#tle #ut important! Suppose that we have a <oint o#*ect called $t and that we write the followin& code=
int + = $t.getR();

The C++ compiler converts this into code alon& the lines of
int + = <oint44getR(?$t);

0here <oint44getR is prototyped as


int <oint44getR(<oint 3*onst this);

This is not le&al C++ code- #ut illustrates what's &oin& on #ehind the scenes whenever you call a mem#er function! The mechanism #ehind mem#er function calls should rarely #e of interest to you as a pro&rammer! /owever- the fact that an A1ar&ument mem#er function is really an K A+1L1ar&ument free function can cause pro#lems in a few places! 8or e)ample- suppose that we want to provide a comparison function for <oints that looks like this=

Chapter ;& Ge$ining Abstractions


*lass <oint { $ubli*4 <oint(int +7o*, int %7o*); int getR() *onst; int getS() *onst; bool *om$are;'o<oints(*onst <oint? one, *onst <oint? t'o) *onst; $rivate4 int +, %; #; bool <oint44*om$are;'o<oints(*onst <oint? one, *onst <oint? t'o) *onst { if(one.+ 1= t'o.+) return one.+ t'o.+; return one.% t'o.%; #

1 ;E1 1

'f you have a ve*tor <oint) that you'd like to pass to the ST sort al&orithm- you'll run into trou#le if you try to use this synta)=
sort(m%Je*tor.begin(), m%Je*tor.end(), ?<oint44*om$are;'o<oints); "" 1roblem

The pro#lem is that sort e)pects a comparison function that takes two parameters and returns a bool! /owever- <oint44*om$are;'o<oints takes three parameters= two points to compare and an invisi#le 4this6 pointer! Thus the a#ove code will &enerate an error! 'f you want to define a comparison or predicate function inside of a class- you'll want that mem#er function to not have an invisi#le this! 0hat does this mean from a practical standpoint> , mem#er function without a this pointer does not have a receiver o#*ect- and thus can only operate on its parameters and any static data mem#ers of the class it's declared in Ksince that data is particular to the class rather than any particular instanceL! 8unctions of this sort are called static member $unctions and can #e created usin& the stati* keyword! 'n the a#ove e)ample with <oint- we could create the <oint comparison function as a stati* mem#er function usin& the followin& synta)=
*lass <oint { $ubli*4 <oint(int +7o*, int %7o*); int getR() *onst; int getS() *onst; stati* bool *om$are;'o<oints(*onst <oint? one, *onst <oint? t'o); $rivate4 int +, %; #; bool <oint44*om$are;'o<oints(*onst <oint? one, *onst <oint? t'o) *onst { if(one.+ 1= t'o.+) return one.+ t'o.+; return one.% t'o.%; #

1 ;E; 1

Chapter ;& Ge$ining Abstractions

"ow- the a#ove call to sort will work since *om$are;'o<oints would no lon&er have a this pointer! Unlike static data mem#ers- when writin& static mem#er functions you do not need to separate the code out into a separate declaration and definition! .ou may want to do so anyway- thou&h! et's return to our earlier e)ample a#out trackin& the num#er of 2indo' instances currently in use! 0hile it's nice that the destructor prints out a messa&e when the last instance has #een cleaned up- we'd prefer a more ro#ust model where we can check how many more copies of the class e)ist! This function is not specific to a particular class instance- so we'll make this function static! 0e'll call this function getIemaining(nstan*es and implement it as shown here=
*lass 2indo' { $ubli*4 "3 ... *onstru*tors, destru*tors, et*. ...3" void dra'2indo'(); stati* int getIemaining(nstan*es(); $rivate4 "3 ... other data members ... 3" stati* <alette shared<al; stati* int num(nstan*es; #; <alette 2indo'44shared<al; int 2indo'44num(nstan*es = 0; int 2indo'44getIemaining(nstan*es() { return num(nstan*es; #

,s with static data- note that when definin& static mem#er functions- you omit the stati* keyword! Gnly put stati* inside the class declaration! .ou can invoke static mem#er functions either usin& the familiar ob>e*t.method synta)- or you can use the fully 5ualified name of the function! 8or e)ample- with the a#ove e)ample- we could check how many remainin& instances there were of the :%5lass class #y callin& getIemaining(nstan*es as follows=
*out 2indo'44getIemaining(nstan*es() endl;

const and static Unfortunately- the *onst and stati* keywords do not always interact intuitively! Gne of the #i&&est issues to #e aware of is that *onst mem#er functions can modify stati* data! 8or e)ample- consider the followin& class=
*lass 5onst6tati*5lass { $ubli*4 void *onst&n() *onst; $rivate4 stati* int stati*9ata; #; int 5onst6tati*5lass44stati*9ata = 0;

Chapter ;& Ge$ining Abstractions Then the followin& implementation of *onst&n is completely valid=
void 5onst6tati*5lass44*onst&n() *onst { !!stati*9ata; #

1 ;E@ 1

,lthou&h the a#ove implementation of *onst&n increments a static data mem#er- the a#ove code will compile and run without any pro#lems! The reason is that the code doesn't modify the receiver o#*ect! Static data mem#ers are not associated with a particular class instance- so modifications to static data mem#ers do not chan&e the state of any one instance of the class! ,dditionally- since stati* mem#er functions don't have a this pointer- they cannot #e declared *onst! 'n the case of getKum(nstan*es- this means that althou&h the function doesn't modify any class data- we still cannot mark it *onst! Integral Class Constants There is one other topic concernin& the interaction of *onst and stati*= class constants! Suppose we want to make a constant varia#le accessi#le only in the conte)t of a class! 0hat we want is a varia#le that's *onst- so it's immuta#le- and stati*- so that all copies of the class share the data! 't's le&al to declare these varia#les like this=
*lass 5lass5onstantE+am$le { $ubli*4 "3 =mitted. 3" $rivate4 stati* *onst int :%5onstant; #; *onst int 5lass5onstantE+am$le44:%5onstant = 8CD;

"ote the *onst in the definition of 5lass5onstantE+am$le44:%5onstant! /owever- since the dou#le declarationHdefinition can #e a #it tedious- C++ has a #uilt1in shorthand you can use when declarin& class constants of inte&ral types! That is- if you have a stati* *onst int or a stati* *onst *har- you can condense the definition and declaration into a sin&le statement #y writin&Q
*lass 5lass5onstantE+am$le { $ubli*4 "3 =mitted. 3" $rivate4 stati* *onst int :%5onstant = 8CDE "" 5ondense into a single line #;

This shorthand is common in professional code! 7e careful when usin& the shorthand- thou&h- #ecause some older compilers won't correctly interpret it! ,lso- #e aware that this only works with integral typesso you cannot initialize a stati* *onst double or stati* *onst float this way! Integrating 6eamlessl/ wit. Con;ersion Constructors 0hen desi&nin& classes- you mi&ht find that certain data types can lo&ically #e converted into o#*ects of the type you're creatin&! 8or e)ample- when writin& the aforementioned rational num#er class- you mi&ht note that raw ints could have a defined conversion to IationalKumber o#*ects! 'n these situations- it

1 ;EA 1

Chapter ;& Ge$ining Abstractions

may #e useful to define implicit conversions #etween the two types! To define implicit conversions- C++ uses conversion constructors- constructors that accept a sin&le parameter and initialize an o#*ect to #e a copy of that parameter! 0hile useful- conversion constructors have several ma*or idiosyncrasies- especially when C++ interprets normal constructors as conversion constructors! This section e)plores implicit type conversionsconversion constructors- and how to prevent codin& errors stemmin& from inadvertent conversion constructors! Im+licit Con;ersions 'n C++- an implicit conversion is a conversion from one type to another that doesn't re5uire an e)plicit typecast! Cerhaps the simplest e)ample is the followin& conversion from an int to a double=
double m%9ouble = 8CD ! E.D8FEF;

/ere- even thou&h 1@D is an int while ;!D1E;E is a double- C++ will implicitly convert it to a double so the operation can proceed smoothly! 0hen C++ performs implicit conversions- it does not 4ma&ically6 fi&ure out how to transform one data type into another! Father- it creates a temporary o#*ect of the correct type that's initialized to the value of the implicitly converted o#*ect! Thus the a#ove code is functionally e5uivalent to
double tem$ = double(m%(nt); double m%9ouble = tem$ ! E.D8FEF;

,s seen here- the compiler created a temporary varia#le of type double- then initialized it #y convertin& the inte&er m%(nt to a double! 0hen C++ performs these conversions- it uses a special function called a conversion constructor to initialize the new o#*ect! Conversion constructors are simply class constructors that accept a sin&le parameter and initialize the new o#*ect to a copy of the parameter! 'n the double e)ample- the newly1created double had the same value as the int parameter! Conversion constructors are surprisin&ly easy to write- and in fact our IationalKumber class already has a conversion constructor! ''ve reprinted this class #elow=
*lass IationalKumber { $ubli*4 IationalKumber(int numerator = 0, int denominator = 8); "3 ... 3" $rivate4 int numerator, denominator; #;

3iven *ust this class- we can write code like the followin&=
IationalKumber m%Kumber = 8CD;

/ow is this possi#le> 137 is an int- not a 4ational@umber! The reason is that C++ interprets this code as a call to the 4ational@umber constructor- passin& in the inte&er 1@D! That is- the code is e5uivalent to
IationalKumber m%Kumber(8CD);

Chapter ;& Ge$ining Abstractions

1 ;E? 1

0hich itself is e5uivalent to the more ver#ose


IationalKumber m%Kumber(8CD, 8);

'n &eneral- if you define a class that has a constructor that can #e called with one ar&ument- C++ will treat this constructor as a conversion constructor- and will translate code of the form
;%$e variable = value;

'nto code of the format


;%$e variable(value);

0hile conversion constructors are 5uite useful in a wide num#er of circumstances- the fact that C++ automatically treats all sin&le1parameter constructors as conversion constructors can lead to convoluted or nonsensical code! Gne of my favorite e)amples of 4conversion1constructors1&one1wron&6 comes from an older version of the CS1067HI ,2T class li#raries! Gri&inally- the CS1067HI Je*tor was defined as
tem$late t%$ename Elem;%$e) *lass Je*tor { $ubli*4 Je*tor(int siUe0int = 80); "" 0int about the siUe of the Je*tor "3 ... 3" #;

"othin& seems all that out1of1the1ordinary here ( we have a Je*tor template class that lets you &ive the class a hint a#out the num#er of elements you will #e storin& in it! /owever- #ecause the constructor accepts a sin&le parameter- C++ will interpret it as a conversion constructor and thus will let us implicitly convert from ints to Je*tors! This can lead to some very stran&e #ehavior! 8or e)ample- &iven the a#ove class definition- consider the followin& code=
Je*tor int) m%Je*tor = 8CD;

This code- while nonsensical- is le&al and e5uivalent to Je*tor int) m%Je*tor(8CD)! 8ortunately- this pro#a#ly won't cause any pro#lems at runtime ( it *ust doesn't make sense in code! /owever- suppose we have the followin& code=
void 9o6omething(Je*tor int)? m%Je*tor) { m%Je*tor = K@77; #

This code is totally le&al even thou&h it makes no lo&ical sense! Since K@77 is .defined to #e 0- The a#ove code will create a new Je*tor int) initialized with the parameter 0 and then assi&n it to m%Je*tor! 'n other words- the a#ove code is e5uivalent to
void 9o6omething(Je*tor int)? m%Je*tor) { Je*tor int) tem$Je*tor(0); m%Je*tor = tem$Je*tor; #

1 ;E6 1

Chapter ;& Ge$ining Abstractions

tem$Je*tor is empty when it's created- so when we assi&n tem$Je*tor to m%Je*tor- we'll set m%Je*tor to the empty vector! Thus the nonsensical line m%Je*tor = 0 is effectively an o#fuscated call to m%Je*tor.*lear()!

Chapter ;& Ge$ining Abstractions

1 ;ED 1

This is a 5uintessential e)ample of why conversion constructors can #e dan&erous! 0hen writin& sin&le1 ar&ument constructors- you run the risk of lettin& C++ interpret your constructor as a conversion constructor!
e5plicit

To prevent pro#lems like the one descri#ed a#ove- C++ provides the e+$li*it keyword to indicate that a constructor must not #e interpreted as a conversion constructor! 'f a constructor is marked e+$li*it- it indicates that the constructor should not #e considered for the purposes of implicit conversions! 8or e)ample- let's look at the current version of the CS1067HI Je*tor- which has its constructor marked e+$li*it=
tem$late t%$ename Elem;%$e) *lass Je*tor { $ubli*4 e+$li*it Je*tor(int siUe0int = 80); "" 0int the siUe of the Je*tor #; "3 ... 3"

"ow- if we write code like


Je*tor int) m%Je*tor = 80;

0e'll &et a compile1time error since there's no implicit conversion from int to Je*tor int)! /oweverwe can still write
Je*tor int) m%Je*tor(80);

0hich is what we were tryin& to accomplish in the first place! Similarly- we eliminate the m%Je*tor = 0 error- and a whole host of other nasty pro#lems! 0hen desi&nin& classes- if you have a sin&le1ar&ument constructor that is not intended as a conversion function- you must mark it e+$li*it to avoid runnin& into the 4implicit conversion6 trap! 0hile indeed this is more work for you as an implementer- it will make your code safer and more sta#le! C.a+ter 6ummar/ Templates can #e used to define a family of a#stractions that depend on an ar#itrary type! The t%$ename keyword is used to declare parameters to a template class! , template class's interface and implementation should #e put into the !h file and no !cpp file should #e created for the class! The t%$ename keyword is also used in front of types nested inside of dependent types! Barkin& a varia#le *onst prevents its value from #ein& chan&ed after the varia#le is initialized! , *onst mem#er function cannot modify any of the class's data mem#ers!
*onst mem#er functions clarify interfaces #y indicatin& which mem#er functions read values and

which mem#er functions write values!

1 ;EE 1

Chapter ;& Ge$ining Abstractions


*onst can have different meanin&s when applied to pointers #ased on where the *onst occurs!

C++ enforces #itwise *onstnessQ it is up to you to ensure that your classes are semantically *onst! The mutable keyword allows you to write semantically *onst functions which are not #itwise *onst! Bem#er initializer lists initialize data mem#ers to particular values #efore the constructor #e&ins runnin&! The stati* keyword allows you to indicate that certain data is shared across all instances of a class!
stati* data mem#ers must #e declared in the !h file and defined in the !cpp file! stati* mem#er functions are functions associated with a class as a whole- rather than a particular

instance of a class!

stati* mem#er functions are invoked #y writin& 5lassKame44fun*tionKame()!

'nte&ral class constants can #e initialized in the #ody of the class and do not need to #e separately defined! Conversion constructors allow classes to #e initialized to values of a different type! The e+$li*it keyword prevents accidental implicit conversions from occurrin&!

!ractice !roblems 1. /ow do you declare a class template> 2. /ow do you implement mem#er functions for a class template> 3. 's there a difference #etween the t%$ename and *lass keywords when declarin& template ar&uments> 4. 0hen is it necessary to preface a type with the t%$ename keyword in a class template> . The followin& line of code declares a mem#er function inside a class=
*onst *har 3 *onst :%&un*tion(*onst string? in$ut) *onst;

J)plain what each *onst in this statement means! !. 0hat is *onst1overloadin&> $. 0hat is the difference #etween semantic *onstness and #itwise *onstness> 6. 0hat is the difference #etween a *onst pointer and a pointer1to1*onst> 7. /ow are *onst references different from re&ular references>

Chapter ;& Ge$ining Abstractions 10. 0hat does the mutable keyword do> 11. 0hat are the steps involved in class construction> 'n what order do they e)ecute> 12. /ow do you declare an initializer list> 13. 0hat is stati* data and how does it differ from re&ular mem#er data> 14. 0hat are the two steps re5uired to add stati* data to a class> 1 . 0hat is a static mem#er function> /ow do you call a static mem#er function> 1!. 0hat is a conversion constructor> 1$. J)plain what the e+$li*it keyword does!

1 ;E< 1

16. The ST ma$'s #racket operator accepts a key and returns a reference to the value associated with that key! 'f the key is not found- the ma$ will insert a new keyHvalue pair so that the returned reference is valid! 's this function #itwise *onst> Semantically *onst> 17. 0hen workin& with pointers to pointers- *onst can #ecome considera#ly trickier to read! 8or e)ample- a *onst int 3 *onst 3 *onst is a *onst pointer to a *onst pointer to a *onst intso neither the pointer- its pointee- or its pointee's pointee can #e chan&ed! 0hat is an int 3 *onst 3> /ow a#out an int 33 *onst 33> 20. The CS1067HI Je*tor has the followin& interface=
tem$late t%$ename Elem;%$e) *lass Je*tor { $ubli*4 Je*tor(int siUe0int = 0); int siUe(); bool isEm$t%(); Elem;%$e getAt(int inde+); void setAt(int inde+, Elem;%$e value); Elem;%$e? o$erator[](int inde+); void add(Elem;%$e elem); void insertAt(int inde+, Elem;%$e elem); void removeAt(int inde+); void *lear(); void ma$All(void fn(Elem;%$e elem)); tem$late t%$ename 5lient9ata;%$e) void ma$All(void fn(Elem;%$e elem, 5lient9ata;%$e ? data), 5lient9ata;%$e ? data); #; (terator iterator();

Bodify this interface so that it is *onst1correct! 5+int& Jou may need to const"overload some o$ these $unctions6

1 ;<0 1

Chapter ;& Ge$ining Abstractions

21. Bodify the Snake simulation code from the earlier e)tended e)ample so that it is *onst1correct! 22. J)plain each of the steps involved in o#*ect construction! 0hy do they occur in the order they do> 0hy are each of them necessary> 23. 0hy must a function with a sin&le parameter with default value must have default values specified for each parameter afterwards> 24. ",S, is currently workin& on Cro*ect Constellation- which aims to resume the lunar landin&s and ultimately to land astronauts on Bars! The spacecraft under development consists of two parts ( an or#ital module called Grion and a landin& vehicle called ,ltair! 2urin& a lunar mission- the Grion vehicle will or#it the Boon while the ,ltair vehicle descends to the surface! The Grion vehicle is desi&ned such that it does not necessarily have to have an ,ltair landin& module and conse5uently can #e used for low Jarth or#it missions in addition to lunar *ourneys! .ou have #een hired to develop the systems software for the spacecraft! 7ecause software correctness and safety are critically important- you want to desi&n the system such that the compiler will alert you to as many potential software pro#lems as possi#le! Suppose that we have two classes- one called =rion:odule and one called Altair:odule! Since every ,ltair landin& vehicle is associated with a sin&le =rion:odule- you want to define the Altair:odule class such that it stores a pointer to its =rion:odule! The Altair:odule class should #e allowed to modify the =rion:odule it points to Ksince it needs to #e a#le to dockHundock and possi#ly to #orrow CCU power for critical landin& maneuversL- #ut it should under no circumstance #e allowed to chan&e which =rion:odule it's associated with! /ere is a skeleton implementation of the Altair:odule class=
*lass Altair:odule $ubli*4 "3 5onstru*tor a**e$ts an =rion:odule re$resenting the =rion 3 s$a*e*raft this Altair is asso*iated 'ith, then sets u$ 3 $arent:odule to $oint to that =rion:odule. 3" Altair:odule(=rion:odule3 o'ner); "3 ... 3" $rivate4 =rion:odule3 $arent:odule; #;

3iven the a#ove description a#out what the Altair:odule should #e a#le to do with its owner =rion:odule- appropriately insert *onst into the definition of the $arent:odule mem#er varia#le! Then- implement the constructor Altair:odule such that the $arent:odule varia#le is initialized to point to the o'ner parameter! 2 . J)plain why stati* mem#er functions cannot #e marked *onst! 2!. 0rite a class @ni[uel%(dentified such that each instance of the class has a uni5ue '2 num#er determined #y takin& the '2 num#er of the previous instance and addin& one! The first instance should have '2 num#er 1! Thus the third instance of the class will have '2 @- the ninety1si)th instance <6- etc! ,lso write a *onst1correct mem#er function get@ni[ue(9 that returns the class's uni5ue '2! 2on't worry a#out reusin& older '2s if their o#*ects &o out of scope!

Chapter ;& Ge$ining Abstractions

1 ;<1 1

2$. The C header file *stdlib) e)ports two functions for random num#er &eneration ( srand- which seeds the randomizer- and rand- which &enerates a pseudorandom int #etween 0 and the constant IAK9L:AR! To make the pseudorandom values of rand appear truly random- you can seed the randomizer usin& the value returned #y the time function e)ported from *time)! The synta) is srand((unsigned int)time(K@77))! 0rite a class IandomGenerator that e)ports a function ne+t that returns a random double in the ran&e N0- 1L! 0hen created- the IandomGenerator class should seed the randomizer with srand only if a previous instance of IandomGenerator hasn't already seeded it! 26. 2oes it make sense to initialize static data mem#ers in a mem#er initializer list> J)plain why or why not! 27. Should you ever mark stati* data mem#ers mutable> 0hy or why not> These practice pro#lems concern a IationalKumber class that encapsulates a rational num#er Kthat is- a num#er e)pressi#le as the 5uotient of two inte&ersL! IationalKumber is declared as follows=
*lass IationalKumber { $ubli*4 IationalKumber(int num = 0, int denom = 8) 4 numerator(num), denominator(denom) {# double getJalue() *onst { return stati*L*ast double)(numerator) " denominator; # void setKumerator(int value) { numerator = value; # void set9enominator(int value) { denominator = value; # $rivate4 int numerator, denominator; #;

The constructor to IationalKumber accepts two parameters that have default values! This means that if you omit one or more of the parameters to IationalKumber- they'll #e filled in usin& the defaults! Thus all three of the followin& lines of code are le&al=
IationalKumber Uero; "" Jalue is 0 " 8 = 0 IationalKumber five(H); "" Jalue is H " 8 = H IationalKumber $iA$$ro+(CHH, 88C); "" Jalue is CHH"88C = C.8G8HMEME0C...

30. J)plain why the IationalKumber constructor is a conversion constructor! 31. 0rite a IealKumber class that encapsulates a real num#er Kany num#er on the num#er lineL! 't should have a conversion constructor that accepts a double and a default constructor that sets the value to zero! 5Aote& Jou only need to write one constructor 2se .ational/um'er as an e4ample6 32. 0rite a conversion constructor that converts IationalKumbers into IealKumbers!

1 ;<; 1

Chapter ;& Ge$ining Abstractions

33. 'f a constructor has two or more ar&uments and no default values- can it #e a conversion constructor> 34. C++ will apply at most one implicit type conversion at a time! That is- if you define three types A- Pand 5 such that A is implicitly converti#le to P and P is implicitly converti#le to 5- C++ will not automatically convert o#*ects of type A to o#*ects of type 5! 3ive an reason for why this mi&ht #e! 5+int& Add another implicit conversion between these types6

C.a+ter 1-8 $+erator $;erloading


_________________________________________________________________________________________________________

Consider the followin& C++ code snippet=


ve*tor string) m%Je*tor(BKum6trings); for(ve*tor string)44iterator itr = m%Je*tor.begin(); itr 1= m%Je*tor.end(); !!itr) 3itr != /Ko' longer1/;

/ere- we create a ve*tor string) of a certain size- then iterate over it concatenatin& 4"ow lon&erR6 to each of the strin&s! Code like this is u#i5uitous in C++- and initially does not appear all that e)citin&! /owever- let's take a closer look at how this code is structured! 8irst- let's look at e)actly what operations we're performin& on the iterator=
ve*tor string) m%Je*tor(BKum6trings); for(ve*tor string)44iterator itr = m%Je*tor.begin(); itr 1= m%Je*tor.end(); !!itr) 3itr != /Ko' longer1/;

'n this simple piece of code- we're comparin& the iterator a&ainst m%Je*tor.end() usin& the 1= operatorincrementin& the iterator with the !! operator- and dereferencin& the iterator with the 3 operator! ,t a hi&h level- this doesn't seem all that out of the ordinary- since ST iterators are desi&ned to look like re&ular pointers and these operators are all well1defined on pointers! 7ut the key thin& to notice is that ST iterators aren)t pointers- they're ob!ects- and 1=- 3- and !! aren't normally defined on o#*ects! 0e can't write code like !!m%Je*tor or 3m%:a$ = 8CD- so why can these operations #e applied to ve*tor string)44iterator> Similarly- notice how we're concatenatin& the strin& 4"ow lon&erR6 onto the end of the strin&=
ve*tor string) m%Je*tor(BKum6trings); for(ve*tor string)44iterator itr = m%Je*tor.begin(); itr 1= m%Je*tor.end(); !!itr) 3itr != /Ko' longer1/;

2espite the fact that string is an o#*ect- somehow C++ 4knows6 what it means to apply != to strings! ,ll of the a#ove e)amples are instances of operator overloading- the a#ility to specify how operators normally applica#le to primitive types can interact with custom classes! Gperator overloadin& is u#i5uitous in professional C++ code and- used correctly- can make your pro&rams more concise- more reada#le- and more template1friendly! There are two overarchin& purposes of operator overloadin&! 8irst- operator overloadin& ena#les your custom classes to act like primitive types! That is- if you have a class like ve*tor that mimics a standard C++ array- you can allow clients to use array notation to access individual elements! Similarly- when desi&nin& a class encapsulatin& a mathematical entity Kfor e)ample- a comple) num#erL- you can let clients apply mathematical operators like !- -- and 3 to your type as thou&h it were #uilt into the lan&ua&e! Second- operator overloadin& ena#les your code to interact correctly with template and li#rary code! 8or e)ample- you can overload the operator to make a class compati#le with the streams li#rary- or the operator to interface with ST containers!

1 ;<A 1

Chapter /%& :perator :verloading

This chapter discusses &eneral topics in operator overloadin&- demonstratin& how to overload some of the more common operators! 't also includes tricks and pitfalls to #e aware of when overloadin& certain operators! A 1ord of 1arning ' would #e remiss to discuss operator overloadin& without first prefacin& it with a warnin&= operator overloadin& is a dou#le1ed&ed sword! 0hen used correctly- operator overloadin& can lead to intuitivetemplate1friendly code that ele&antly performs comple) operations #ehind the scenes! /oweverincorrectly overloaded operators can lead to incredi#ly su#tle #u&s! Seemin&ly innocuous code alon& the lines of 3m%(tr = H can cause serious pro#lems if implemented incorrectly- and without a solid understandin& of how to overload operators you may find yourself in serious trou#le! There is a pearl of desi&n wisdom that is particularly applica#le to operator overloadin&= The Principle of Least Astonishment& , function's name should communicate its #ehavior and should #e consistent with other namin& conventions and idioms! The principle of least astonishment should #e fairly o#vious ( you should desi&n functions so that clients can understand what those functions do simply #y lookin& at the functions' namesQ that is- clients of your code should not #e 4astonished6 that a function with one name does somethin& entirely different! 8or e)ample- a function named 9o6omething violates the principle of least astonishment #ecause it doesn't communicate what it does- and a function called 5om$ute<rimes that reads a &rocery list from a file violates the principle #ecause the name of the function is completely different from the operation it performs! /owever- other violations of the principle of least astonishment are not as #latant! 8or e)amplea custom container class whose em$t% mem#er function erases the contents of the container violates the principle of least astonishment #ecause C++ pro&rammers e)pect em$t% to mean 4is the container empty>6 rather than 4empty the container!6 Similarly- a class that is #itwise *onst #ut not semantically *onst violates the principle- since pro&rammers assume that o#*ects can't #e modified #y *onst mem#er functions! 0hen workin& with operator overloadin&- it is crucial to adhere to the principle of least astonishment! C+ + lets you redefine almost all of the #uilt1in operators however you choose- meanin& that it's possi#le to create code that does somethin& completely different from what C++ pro&rammers mi&ht e)pect! 8or e)ample- suppose that you are workin& on a &roup pro*ect and that one of your teammates writes a class 5ustomJe*tor that acts like the ST ve*tor #ut which performs some additional operations #ehind the scenes! .our pro&ram contains a small #u&- so you look over your teammate's code and find the followin& code at one point=
5ustomJe*tor one = "3 ... 3", t'o = "3 ... 3"; one \= t'o;

0hat does the line one \= t'o do> Syntactically- this says 4take the remainder when dividin& one #y t'o- then store the result #ack in one!6 7ut this makes no sense ( how can you divide one 5ustomJe*tor #y another> .ou ask your teammate a#out this- and he informs you that the \= operator means 4remove all elements from one that are also in t'o!6 This is an e&re&ious violation of the principle of least astonishment! The code neither communicates what it does nor adheres to e)istin& convention- since the semantics of the \= operator are meanin&less when applied to linear data structures! This is not to say- of course- that havin& the a#ility to remove all elements from one 5ustomJe*tor that are contained in another is a #ad idea ( in fact- it can #e 5uite useful ( #ut this functionality should #e provided #y a properly1named mem#er function rather than a cryptically1overloaded operator! 8or e)ample- consider the followin& code=

Chapter /%& :perator :verloading

1 ;<? 1

5ustomJe*tor one = "3 ... 3", t'o = "3 ... 3"; one.removeAll(n(t'o);

This code accomplishes the same task as the a#ove code- #ut does so #y e)plicitly indicatin& what operation is #ein& performed! This code is much less likely to confuse readers and is far more descriptive than #efore! ,s another e)ample- suppose that your teammate also implements a class called 5ustom6tring that acts like the standard string type- #ut provides additional functionality! .ou write the followin& code=
5ustom6tring one = /0ello/, t'o = / 2orld/; one != t'o; *out one ! /1/ endl;

'ntuitively- this should create two strin&s- then concatenate the second onto the end of the first! "e)t- the code prints out one followed #y an e)clamation point- yieldin& 4/ello 0orldR6 Unfortunately- when you compile this code- you &et an unusual error messa&e ( for some reason the code one != t'o compiles correctly- #ut the compiler re*ects the code one ! /1/! 'n other words- your teammate has made it le&al to concatenate two strin&s usin& !=- #ut not #y usin& !! ,&ain- think #ack to the principle of least astonishment! Cro&rammers tacitly e)pect that o#*ects that can #e added with ! can #e added with != and vice1versa- and providin& only half of this functionality is likely to confuse code clients! The moral of this story is simple= when overloadin& operators- make sure that you adhere to e)istin& conventions! 'f you don't- you will end up with code that is either incorrect- confusin&- or #oth! /opefully this &rim introduction has not discoura&ed you from usin& operator overloadin&! Gperator overloadin& is e)traordinarily useful and you will not #e disappointed with the possi#ilities that are a#out to open up to you! 0ith that said- let's #e&in discussin& the mechanics #ehind this powerful techni5ue! Defining $;erloaded $+erators 0e introduced operator overloadin& as a mechanism for redefinin& how the #uilt1in operators apply to custom classes! Syntactically- how do we communicate to the C++ compiler that we want to redefine these operators> The answer is somewhat odd! /ere's the ori&inal motivatin& e)ample we had at the #e&innin& of the chapter=
ve*tor string) m%Je*tor(BKum6trings); for(ve*tor string)44iterator itr = m%Je*tor.begin(); itr 1= m%Je*tor.end(); !!itr) 3itr != /Ko' longer1/;

0hen you provide this code to the C++ compiler- it interprets it as follows=
ve*tor string) m%Je*tor(BKum6trings); for(ve*tor string)44iterator itr = m%Je*tor.begin(); o$erator1= (itr, m%Je*tor.end())E itr.o$erator!!()) (itr.o$erator3()).o$erator !=(/Ko' longer1/);

"otice that everywhere we used the #uilt1in operator in con*unction with an o#*ect- the compiler reinterpreted the operator as a call to a specially1named function called o$erator op- where op is the particular operator we used! Thus itr 1= m%Je*tor.end() translated into o$erator1= (itr, m%Je*tor.end())- !!itr was interpreted as itr.o$erator!!()- etc! ,lthou&h these functions may

1 ;<6 1

Chapter /%& :perator :verloading

have cryptic names- they're *ust re&ular functions! Gperator overloadin& is simply synta4 sugar- a way of rewritin& one operation Kin this case- function callsL usin& a different synta) Khere- the #uilt1in operatorsL! Gverloaded operators are not somehow 4more efficient6 than other functions simply #ecause the function calls aren't e)plicit- nor are they treated any different from re&ular functions! They are special only in that they can are invoked usin& the #uilt1in operators rather than throu&h an e)plicit function calls! 'f you'll notice- some of the operators used a#ove were translated into mem#er function calls Kparticularly !! and 3L- while others K1=L were translated into calls to free functions! 0ith a few e)ceptions- any operator can #e overloaded as either a free function or a mem#er function! 2eterminin& whether to use free functions or mem#er functions for overloaded operators is a #it tricky- and we'll discuss it more as we continue our tour of overloaded operators! Jach of C++'s #uilt1in operators has a certain num#er of operands! 8or e)ample- the plus operator K a ! bL has two operands correspondin& to the values on the left1 and ri&ht1hand sides of the operator! The pointer dereference operator K3itrL- on the other hand- takes in only one operand= the pointer to dereference! 0hen definin& a function that is an overloaded operator- you will need to ensure that your function has one parameter for each of the operator's operands! 8or e)ample- suppose that we want to define a type IationalKumber which encapsulates a rational num#er Ka ratio of two inte&ersL! 7ecause it's mathematically sound to add two rational num#ers- we mi&ht want to consider overloadin& the ! operator as applied to IationalKumber so that we can add IationalKumbers usin& an intuitive synta)! 0hat would such a function look like> 'f we implement the ! operator as a mem#er function of IationalKumber- the synta) would #e as follows=
*lass IationalKumber { $ubli*4 *onst IationalKumber o$erator! (*onst IationalKumber? rhs) *onst; #; "3 ... et*. ... 3"

K.ou mi&ht #e wonderin& why the return type is *onst IationalKumber! 8or now- you can i&nore that!!! we'll pick this up in the ne)t sectionL 0ith o$erator! defined this way- then addition of IationalKumbers will #e translated into calls to the mem#er function o$erator! on IationalKumber! 8or e)ample- the followin& code=
IationalKumber one, t'o; IationalKumber three = one ! t'o;

will #e interpreted #y the compiler as


IationalKumber one, t'o; IationalKumber three = one.o$erator !(t'o);

"otice that the code one ! t'o was interpreted as one.o$erator! (t'o)! That is- the receiver o#*ect of the o$erator! function is the left1hand operand- while the ar&ument is the ri&ht1hand ar&ument! This is not a coincidence- and in fact C++ will &uarantee that the relative orderin& of the operands is preserved! one ! t'o will never #e interpreted as t'o.o$erator! (one) under any circumstance- and our implementation of o$erator! can take this into account! ,lternatively- we could consider implementin& o$erator! as a free function takin& in two ar&uments! 'f we chose this approach- then the interface for IationalKumber would #e as follows=

Chapter /%& :perator :verloading

1 ;<D 1

1 ;<E 1
*lass IationalKumber { $ubli*4 "3 ... et*. ... 3" #;

Chapter /%& :perator :verloading

*onst IationalKumber o$erator! (*onst IationalKumber? lhs, *onst IationalKumber? rhs);

'n this case- the code


IationalKumber one, t'o; IationalKumber three = one ! t'o;

would #e interpreted #y the compiler as


IationalKumber one, t'o; IationalKumber three = o$erator! (one, t'o);

,&ain- the relative orderin& of the parameters is &uaranteed to #e sta#le- and so you can assume that the first parameter to o$erator! will always #e on the left1hand side of the operator! 'n some cases- two operators are syntactically identical #ut have different meanin&s! 8or e)ample- the operator can refer either to the #inary su#traction operator K a - bL or the unary ne&ation operator K -aL! 'f overload the - operator- how does the compiler know whether your overloaded operator is the unary or #inary version of -> The answer is rather strai&htforward= if the function operates on two pieces of datathe compiler treats o$erator- as the #inary su#traction operator- and if the function uses *ust one piece of data it's considered to #e the unary ne&ation operator! et's make this discussion a #it more concrete! Suppose that we want to implement su#traction on the IationalKumber class! 7ecause the #inary su#traction operator has two operands- we would provide su#traction as an overloaded operator either as a free function=
*onst IationalKumber o$erator- (*onst IationalKumber? lhs, *onst IationalKumber? rhs);

or- alternatively- as a mem#er function=


*lass IationalKumber { $ubli*4 *onst IationalKumber o$erator- (*onst IationalKumber? rhs) *onst; #; "3 ... et*. ... 3"

"otice that #oth of these functions operate on two pieces of data! 'n the first case- the function takes in two parameters- and in the second- the receiver o#*ect is one piece of data and the parameter is the other! 'f we now want to provide an implementation of o$erator- which represents the unary ne&ation operator- we could implement it as a free function with the followin& si&nature=
*onst IationalKumber o$erator- (*onst IationalKumber? arg);

Gr as a mem#er function of this form=

Chapter /%& :perator :verloading


*lass IationalKumber { $ubli*4 *onst IationalKumber o$erator- () *onst; #; "3 ... et*. ... 3"

1 ;<< 1

,&ain- don't worry a#out why the return type is a *onst IationalKumber! 0e'll address this shortly! 1.at $+erator $;erloading Cannot Do 0hen overloadin& operators- you cannot define #rand1new operators like . or X! ,fter all- C++ wouldn't know the associativity or proper synta) for the operator Kis one . t'o ! three interpreted as (one . t'o) ! three or one . (t'o ! three)>L ,dditionally- you cannot overload any of the followin& operators= Operator
44 . T4 .3 siUeof t%$eid

Syntax
:%5lass44value one.value a ) b T -8 4 8 a.3m%5lass<tr; siUeof(:%5lass) t%$eid(:%5lass)

Name Scope resolution Bem#er selection Ternary conditional Cointer1to1mem#er selection K#eyond the scope of this te)tL Size of o#*ect Funtime type information operator Typecast

(;) (int) m%5lass; stati*L*ast d%nami*L*ast reinter$retL*ast *onstL*ast

"ote that operator overloadin& only lets you define what #uilt1in operators mean when applied to ob!ects! .ou cannot use operator overloadin& to redefine what addition means as applied to ints- nor can you chan&e how pointers are dereferenced! Then a&ain- #y the principle of least astonishment- you wouldn't want to do this anyway! =;alues and 4;alues 7efore we #e&in e)plorin& some of the implementation issues associated with overloaded operators- we need to take a 5uick detour to e)plore two concepts from pro&rammin& lan&ua&e theory called lvalues and rvalues! values and rvalues stand for 4left values6 and 4ri&ht values6 are are so1named #ecause of where they can appear in an assi&nment statement! 'n particular- an lvalue is a value that can #e on the left1hand side of an assi&nment- and an rvalue is a value that can only #e on the ri&ht1hand side of an assi&nment! 8or e)ample- in the statement + = H- + is an lvalue and H is an rvalue! Similarly- in 3itr = 8CD- 3itr is the lvalue and 8CD is the rvalue! 't is ille&al to put an rvalue on the left1hand side of an assi&nment statement! 8or e)ample- 8CD = GE is ille&al #ecause 8CD is an rvalue- and Get(nteger() = + is ille&al #ecause the return value of Get(nteger() is an rvalue! /owever- it is le&al to put an lvalue on the ri&ht1hand side of an assi&nmentas in + = % or + = 3itr!

1 @00 1

Chapter /%& :perator :verloading

,t this point the distinction #etween lvalues and rvalues seems purely academic! 4Gkay-6 you mi&ht say4some thin&s can #e put on the left1hand side of an assi&nment statement and some thin&s can't! So what>6 0hen writin& overloaded operators- the lvalueHrvalue distinction is e)tremely important! 7ecause operator overloadin& lets us define what the #uilt1in operators mean when applied to o#*ects of class typewe have to #e very careful that overloaded operators return lvalues and rvalues appropriately! 8or e)ample- #y default the ! operator returns an rvalueQ that is- it makes no sense to write
(+ ! %) = H;

Since this would assi&n the value ? to the result of addin& + and %! /owever- if we're not careful when overloadin& the ! operator- we mi&ht accidentally make the a#ove statement le&al and pave the way for nonsensical #ut le&al code! Similarly- it is le&al to write
m%Arra%[H] = 8CD;

So the element1selection operator Kthe #rackets operatorL should #e sure to return an lvalue instead of an rvalue! 8ailure to do so will make the a#ove code ille&al when applied to custom classes! Fecall that an overloaded operator is a specially1named function invoked when the operator is applied to an o#*ect of a custom class type! Thus the code
(+ ! %) = H;

is e5uivalent to
o$erator! (+, %) = H;

if either + or % is an o#*ect! Similarly- if m%Arra% is an o#*ect- the code


m%Arra%[H] = 8CD;

is e5uivalent to
m%Arra%.o$erator[](H) = 8CD;

To ensure that these functions have the correct semantics- we need to make sure that o$erator! returns an rvalue and that o$erator[] returns an lvalue! /ow can we enforce this restriction> The answer has to do with the return type of the two functions! To make a function that returns an lvalue- have that function return a non1*onst reference! 8or e)ample- the followin& function returns an lvalue=
string? 7Jalue&un*tion();

7ecause a reference is *ust another name for a varia#le or memory location- this function hands #ack a reference to an lvalue and its return value can #e treated as such! To have a function return an rvalue- have that function return a *onst o#*ect #y value! Thus the function
*onst string IJalue&un*tion();

Chapter /%& :perator :verloading

1 @01 1

returns an rvalue!P The reason that this trick works is that if we have a function that returns a *onst o#*ect- then code like
IJalue&un*tion() = 8CD;

is ille&al #ecause the return value of IJalue&un*tion is marked *onst! values and rvalues are difficult to understand in the a#stract- #ut as we #e&in to actually overload particular operators the difference should #ecome clearer! $;erloading t.e )lement 6election $+erator et's #e&in our descent into the realm of operator overloadin& #y discussin& the overloaded element selection operator Kthe [ ] operator- used to select elements from arraysL! .ou've #een usin& the overloaded element selection operator ever since you encountered the string and ve*tor classes! 8or e)ample- the followin& code uses the ve*tor's overloaded element selection operator=
for(int i = 0; i m%Je*tor.siUe(); !!i) m%Je*tor[i] = 8CD;

'n the a#ove e)ample- while it looks like we're treatin& the ve*tor as a primitive array- we are instead callin& the a function named o$erator []- passin& i as a parameter! Thus the a#ove code is e5uivalent to
for(int i = 0; i m%Je*tor.siUe(); !!i) m%Je*tor.o$erator [](i) = 8CD;

To write a custom element selection operator- you write a mem#er function called o$erator [] that accepts as its parameter the value that &oes inside the #rackets! "ote that while this parameter can #e of any type Kthink of the ST ma$L- you can only have a sin&le value inside the #rackets! This may seem like an ar#itrary restriction- #ut makes sense in the conte)t of the principle of least astonishment= you can't put multiple values inside the #rackets when workin& with raw C++ arrays- so you shouldn't do so when workin& with custom o#*ects! 0hen writin& o$erator []- as with all overloaded operators- you're free to return o#*ects of whatever type you'd like! /owever- remem#er that when overloadin& operators- it's essential to maintain the same functionality you'd e)pect from the naturally1occurrin& uses of the operator! 'n the case of the element selection operator- this means that the return value should #e an lvalue- and in particular a reference to some internal class data determined #y the inde)! 8or e)ample- here's one possi#le prototype of the C++ string's element selection operator=
*lass string { $ubli*4 "3 ... 3" #; *har? o$erator [] (siUeLt $osition);

P Technically speakin& any non1reference value returned from a function is an rvalue! /owever- when returnin& o#*ects from a function- the rvalueHlvalue distinction is #lurred #ecause the assi&nment operator and other operators are mem#er functions that can #e invoked re&ardless of whether the receiver is an rvalue or lvalue! The additional *onst closes this loophole!

1 @0; 1

Chapter /%& :perator :verloading

/ere- o$erator[] takes in an int representin& the inde) and returns a reference to the character at that position in the string! 'f string is implemented as a wrapper for a raw C strin&- then one possi#le implementation for o$erator[] mi&ht #e
*har? string44o$erator[] (siUeLt inde+) { return the6tring[inde+]; "" Assuming the6tring is an arra% of *hara*ters #

7ecause o$erator[] returns a reference to an element- it is common to find o$erator[] paired with a *onst1overload that returns a *onst reference to an element in the case where the receiver o#*ect is immuta#le! There are e)ceptions to this rule- such as the ST ma$- #ut in the case of string we should provide a *onst overload- as shown here=
*lass string { $ubli*4 "3 ... 3" *har? o$erator [] (siUeLt $osition); *onst *har? o$erator [] (siUeLt $osition) *onst; #;

The implementation of the *onst o$erator[] function is identical to the non1*onst version! 0hen writin& the element selection operator- it's completely le&al to modify the receiver o#*ect in response to a re5uest! 8or e)ample- with the ST ma$- o$erator[] will silently create a new o#*ect and return a reference to it if the key isn't already in the ma$! This is part of the #eauty of overloaded operators ( you're allowed to perform any necessary steps to ensure that the operator makes sense! Unfortunately- if your class encapsulates a multidimensional o#*ect- such as a matri) or hierarchical key1 value system- you cannot 4overload the [][] operator!6 , class is only allowed to overload one level of the #racket synta)Q it's not le&al to desi&n o#*ects that dou#ly1overload []!P $;erloading Com+ound Assignment $+erators The compound assi&nment operators are operators of the form op= Kfor e)ample- != and 3=L that update an o#*ect's value #ut do not overwrite it! Compound assi&nment operators are often declared as mem#er functions with the followin& #asic prototype=
:%5lass? o$erator != (*onst <arameter;%$e? $aram)

8or e)ample- suppose we have the followin& class- which represents a vector in three1dimensional space=
*lass Je*torC9 { $ubli*4 "3 ... 3" $rivate4 stati* *onst int K@:L5==I9(KA;E6 = C; double *oordinates[K@:L5==I9(KA;E6]; #;

P There is a techni5ue called pro4y ob!ects that can make code alon& the lines of m%=b>e*t[+][%] le&al! The trick is to define an o$erator[] function for the class that returns another o#*ect that itself overloads o$erator[]! 0e'll see this trick used in the upcomin& chapter on a custom grid class!

Chapter /%& :perator :verloading

1 @0@ 1

't is le&al to add two mathematical vectors to one anotherQ the result is the vector whose components are the pairwise sum of each of the components of the source vectors! 'f we wanted to define a != operator for Je*torC9 to let us perform this addition- we would modify the interface of Je*torC9 as follows=
*lass Je*torC9 { $ubli*4 "3 ... 3" Je*torC9? o$erator!= (*onst Je*torC9? other); $rivate4 stati* *onst int K@:L5==I9(KA;E6 = C; double *oordinates[K@:L5==I9(KA;E6]; #;

This could then #e implemented as


Je*torC9? Je*torC944o$erator !=(*onst Je*torC9? other) { for(int i = 0; i K@:L5==I9(KA;E6; !!i) *oordinates[i] != other.*oordinates[i]; return 3this; #

'f you'll notice- o$erator!= returns 3this- a reference to the receiver o#*ect! Fecall that when overloadin& operators- you should make sure to define your operators such that they work identically to the C++ #uilt1in operators! 't turns out that the != operator yields an lvalue- so the code #elow- thou&h the 5uintessence of a#ysmal style- is perfectly le&al=
int one, t'o, three, four; (one != t'o) != (three != four);

Since overloaded operators let custom types act like primitives- the followin& code should also compile=
Je*torC9 one, t'o, three, four; (one != t'o) != (three != four);

'f we e)pand out the calls to the overloaded != operator- we find that this is e5uivalent to
Je*torC9 one, t'o, three, four; one.o$erator!=(t'o).o$erator !=(three.o$erator !=(four));

"ote that the reference returned #y one.o$erator!=(t'o) then has its own != operator invoked! Since o$erator != is not marked *onst- had the != operator returned a *onst reference- this code would have #een ille&al! Bake sure to have any KcompoundL assi&nment operator return 3this as a non1*onst reference! Unlike the re&ular assi&nment operator- with the compound assi&nment operator it's commonly meanin&ful to accept o#*ects of different types as parameters! 8or e)ample- we mi&ht want to make e)pressions like m%Je*tor 3= 8CD for Je*torC9s meanin&ful as a scalin& operation! 'n this case- we can simply define an o$erator 3= that accepts a double as its parameter! 8or e)ample=

1 @0A 1
*lass Je*torC9 { $ubli*4 "3 ... 3" Je*torC9? o$erator != (*onst Je*torC9? other); Je*torC9? o$erator 3= (double s*ale&a*tor); $rivate4 stati* *onst int K@:L5==I9(KA;E6 = C; double *oordinates[K@:L5==I9(KA;E6]; #;

Chapter /%& :perator :verloading

2espite the fact that the receiver and parameter have different types- this is perfectly le&al C++! /ere's one possi#le implementation=
Je*torC9? Je*torC944o$erator3= (double s*ale&a*tor) { for(int B = 0; B K@:L5==I9(KA;E6; !!B) *oordinates[B] 3= s*ale&a*tor; return 3this; #

+ltho#/h we have implemented o$erator!= and o$erator3= *or the Je*torC9 class, "LL will not a#tomatically provide #s an implementation o* o$erator-= and o$erator"=, despite the *act that those *#nctions can easily be implemented as wrapped calls to the operators we.ve already implemented. This mi/ht seem co#nterint#itive, b#t prevents errors *rom cases where seemin/ly symmetric operations are #nde*ined. Jor e4ample, it is le/al to m#ltiply a vector and a matri4, tho#/h the division is #nde*ined. Jor completeness. sa0e, we.ll prototype o$erator-= and o$erator"= as shown hereF
*lass Je*torC9 { $ubli*4 "3 ... 3" Je*torC9? o$erator != (*onst Je*torC9? other); Je*torC9? o$erator -= (*onst Je*torC9? other); Je*torC9? o$erator 3= (double s*ale&a*tor); Je*torC9? o$erator "= (double s*ale&a*tor); $rivate4 stati* *onst int K@:L5==I9(KA;E6 = C; double *oordinates[K@:L5==I9(KA;E6]; #;

-ow, how mi/ht we /o abo#t implementin/ these operators: o$erator"= is the simplest o* the two and can be implemented as *ollowsF
Je*torC9? Je*torC944o$erator "= (double s*ale&a*tor) { 3this 3= 8.0 " s*ale&a*tor; return 3this; #

This implementation, tho#/h cryptic, is act#ally E#ite ele/ant. The *irst line, 3this 3= 8.0 " s*ale&a*tor, says that we sho#ld m#ltiply the receiver obAect ( 3this) by the reciprocal o* s*ale&a*tor. The 3= operator is the compo#nd m#ltiplication assi/nment operator that we wrote above, so this code invo0es o$erator3= on the receiver. 2n *act, this code is eE#ivalent to

Chapter /%& :perator :verloading


Je*torC9? Je*torC944o$erator "= (double s*ale&a*tor) { o$erator3= (8.0 " s*ale&a*tor); return 3this; M

1 @0? 1

,ependin/ on yo#r taste, yo# mi/ht *ind this partic#lar synta4 more readable than the *irst version. Jeel *ree to #se either version. -ow, how wo#ld we implement o$erator-=, which per*orms a componentwise s#btraction o* two Je*torC9s: +t a hi/h level, s#btractin/ one vector *rom another is eE#al to addin/ the inverse o* the second vector to the *irst, so we mi/ht want to write code li0e thisF
Je*torC9? Je*torC944o$erator -= (*onst Je*torC9? other) { 3this != -other; return 3this; #

That is, we add -other to the receiver obAect. &#t this code is ille/al beca#se we haven.t de*ined the #nary min#s operator as applied to Je*torC9s. -ot to worry G we can overload this operator as well. The synta4 *or this *#nction is as *ollowsF
*lass Je*torC9 { $ubli*4 "3 ... 3" Je*torC9? o$erator != (*onst Je*torC9? other); Je*torC9? o$erator -= (*onst Je*torC9? other); Je*torC9? o$erator 3= (double s*ale&a*tor); Je*torC9? o$erator "= (double s*ale&a*tor); *onst Je*torC9 o$erator- () *onst; $rivate4 stati* *onst int K@:L5==I9(KA;E6 = C; double *oordinates[K@:L5==I9(KA;E6]; M5

There are *o#r pieces o* in*ormation abo#t this *#nction that deserve attentionF The name o* the #nary min#s *#nction is o$erator -. The *#nction ta0es no parameters. This lets "LL 0now that the *#nction is the unary min#s *#nction (2.e. -m%Je*tor) rather than the binary min#s *#nction (m%Je*tor Q m%=therJe*tor). The *#nction ret#rns a *onst Je*torC9. The #nary min#s *#nction ret#rns an rvalue rather than an lvalue, since code li0e -+ = 8CD is ille/al. +s mentioned above, this means that the ret#rn val#e o* this *#nction sho#ld be a *onst Je*torC9. The *#nction is mar0ed *onst. +pplyin/ the #nary min#s to an obAect doesn.t chan/e its val#e, and to en*orce this restriction we.ll mar0 o$erator Q *onst.

3ne possible implementation o* o$erator- is as *ollowsF

1 @06 1
*onst Je*torC9 Je*torC944o$erator- () *onst { Je*torC9 result; for(int B = 0; B K@:L5==I9(KA;E6; !!B) result.*oordinates[B] = -*oordinates[B]; return result; #

Chapter /%& :perator :verloading

-ote that the ret#rn type o* this *#nction is *onst Je*torC9 while the type o* result inside the *#nction is Je*torC9. This isn.t a problem, since ret#rnin/ an obAect *rom a *#nction yields a new temporary obAect and it.s le/al to initiali=e a *onst Je*torC9 #sin/ a Je*torC9. Hhen writin/ compo#nd assi/nment operators, as when writin/ re/#lar assi/nment operators, yo# m#st be care*#l that sel*)assi/nment wor0s correctly. 2n the above e4ample with Je*torC9.s compo#nd assi/nment operators we didn.t need to worry abo#t this beca#se the code was str#ct#red correctly. However, when wor0in/ with the "LL string.s != operator, since the string needs to allocate a new b#**er capable o* holdin/ the c#rrent string appended to itsel*, it wo#ld need to handle the sel*)assi/nment case, either by e4plicitly chec0in/ *or sel*)assi/nment or thro#/h some other means. $;erloading (at.ematical $+erators 'n the previous section- we provided overloaded versions of the != family of operators! Thus- we can now write classes for which e)pressions of the form one != t'o are valid! /owever- the seemin&ly e5uivalent e)pression one = one ! t'o will still not compile- since we haven't provided an implementation of the lone ! operator! C++ will not automatically provide implementations of related operators &iven a sin&le overloaded operator- since in some cases this could result in nonsensical or meanin&less #ehavior! The #uilt1in mathematical operators yield rvalues- so code like (+ ! %) = 8CD will not compile! Conse5uently- when overloadin& the mathematical operators- make sure they return rvalues as well #y havin& them return *onst o#*ects! et's consider an implementation of o$erator ! for our Je*torC9 class! 7ecause the operator yields an rvalue- we're supposed to return a *onst Je*torC9- and #ased on our knowled&e of parameter passin&we know that we should accept a *onst Je*torC9 ? as a parameter! There's one more #it we're for&ettin&- thou&h- and that's to mark the o$erator ! *#nction *onst- since o$erator ! creates a new o#*ect and doesn't modify either of the values used in the arithmetic statement! This results in the followin& code
*lass Je*torC9 { $ubli*4 "3 ... 3" Je*torC9? o$erator != (*onst Je*torC9? other); *onst Je*torC9 o$erator! (*onst Je*torC9? other); Je*torC9? o$erator -= (*onst Je*torC9? other); Je*torC9? o$erator 3= (double s*ale&a*tor); Je*torC9? o$erator "= (double s*ale&a*tor); *onst Je*torC9 o$erator- () *onst; $rivate4 stati* *onst int K@:L5==I9(KA;E6 = C; double *oordinates[K@:L5==I9(KA;E6]; M5

Chapter /%& :perator :verloading

1 @0D 1

/ow are we to implement this function> 0e could *ust do a component1#y1component addition- #ut it's actually much easier to *ust write the function in terms of our o$erator !=! The full version of this code is shown #elow=
*onst Je*torC9 Je*torC944o$erator !(*onst Je*torC9? other) *onst { Je*torCd result = 3this; "" :aBe a dee$ *o$% of this Je*torC9. result != other; "" @se e+isting addition *ode. return result; #

"ow- all of the code for o$erator ! is unified- which helps cut down on codin& errors! There is an interestin& and common case we haven't addressed yet ( what if one of the operands isn't of the same type as the class> 8or e)ample- if you have a :atri+ class that encapsulates a @)@ matri)- as shown here=
*lass :atri+ { $ubli*4 "3 ... 3" :atri+? o$erator 3= (double s*alar)E "" 6*ale all entries $rivate4 stati* *onst int :A;I(RL6(ZE = C; double entries[:A;I(RL6(ZE][:A;I(RL6(ZE]; #;

"ote that there is a defined 3= operator that scales all elements in the matri) #y a double factor! Thus code like m%:atri+ 3= E.D8FEF is well1defined! /owever- since there's no defined o$erator 3currently we cannot write m%:atri+ = m%:atri+ 3 E.D8FEF! 'nitially- you mi&ht think that we could define o$erator 3 *ust as we did o$erator ! in the previous e)ample! 0hile this will work in most cases- it will lead to some pro#lems we'll need to address later! 8or now- however- let's add the mem#er function o$erator 3 to :atri+- which is defined as
*onst :atri+ :atri+44o$erator 3(double s*alar) *onst { :%:atri+ result = 3this; result 3= s*alar; return result; #

"ow- we can write e)pressions like m%:atri+ = m%:atri+ 3 E.D8FEF! /owever- what happens if we write code like m%:atri+ = E.D8FEF 3 m%:atri+> This is a semantically meanin&ful e)pression- #ut unfortunately it won't compile! 0hen interpretin& overloaded operators- C++ will always preserve the order of values in an e)pression!P Thus E.D8FEF 3 m%:atri+ is not the same as m%:atri+ 3 E.D8FEF! Femem#er that the reason that m%:atri+ 3 E.D8FEF is le&al is #ecause it's e5uivalent to m%:atri+.o$erator 3(E.D8FEF)! The e)pression E.D8FEF 3 m%:atri+- on the other hand- is ille&al #ecause C++ will try to e)pand it into (E.D8FEF).o$erator 3(m%:atri+)- which makes no sense!

P Gne ma*or reason for this is that sometimes the arithmetic operators won't #e commutative! 8or e)ample- &iven matrices A and B- AB is not necessarily the same as BA- and if C++ were to ar#itrarily flip parameters it could result in some e)tremely difficult1to1track #u&s!

1 @0E 1

Chapter /%& :perator :verloading

To fi) this- we can make o$erator 3 a free function that accepts two parameters- a double and a :atri+and returns a *onst :atri+! Thus code like E.D8FEF 3 m%:atri+ will e)pand into calls to o$erator 3(E.D8FEF, m%:atri+)! The new version of o$erator 3 is defined #elow=
*onst :atri+ o$erator 3 (double s*alar, *onst :atri+? matri+) { :atri+ result = 3matri+; matri+ 3= s*alar; return result; #

7ut here we run into the same pro#lem as #efore if we write m%:atri+ 3 E.D8FEF- since we haven't defined a function acceptin& a :atri+ as its first parameter and an double as its second! To fi) this- we'll define a second free function o$erator 3 with the parameters reversed that's implemented as a call to the other version=
*onst :atri+ o$erator 3(*onst :atri+? matri+, double s*alar) { return s*alar 3 matri+E "" 5alls o$erator3 (s*alar, matri+) #

,s a &eneral rule- mathematical operators like ! should always #e implemented as free functions! This prevents pro#lems like those descri#ed here! Gne important point to notice a#out overloadin& the mathematical operators versus the compound assi&nment operators is that it's considera#ly faster to use the compound assi&nment operators over the standalone mathematical operators! "ot only do the compound assi&nment operators work in1place Kthat is- they modify e)istin& o#*ectsL- #ut they also return references instead of full o#*ects! 8rom a performance standpoint- this means that &iven these three strings=
string one = /;his /; string t'o = /is a /; string three = /string1/;

Consider these two code snippets to concatenate all three strin&s=


/G Nsing DO G/ string m%6tring = one; m%6tring != t'o; m%6tring != three; /G Nsing D G/ string m%6tring = one ! t'o ! three

Gddly- the second version of this code is considera#ly slower than the first #ecause the ! operator &enerates temporary o#*ects! Femem#er that one ! t'o ! three is e5uivalent to
o$erator !(one, o$erator !(t'o, three))

Jach call to o$erator ! returns a new string formed #y concatenatin& the parameters- so the code one ! t'o ! three creates two temporary string o#*ects! The first version- on the other hand- &enerates no temporary o#*ects since the != operator works in1place! Thus while the first version is less si&htly- it is si&nificantly faster than the second!

Chapter /%& :perator :verloading $;erloading DD and --

1 @0< 1

Gverloadin& the increment and decrement operators can #e a #it tricky #ecause there are two versions of each operator= pre$i4 and post$i4! Fecall that +!! and !!+ are different operations ( the first will evaluate to the value of +- then increment +- while the second will increment + and then evaluate to the updated value of +! .ou can see this #elow=
int + = 0 *out +!! *out + + = 0; *out *out !!+ + endl; "" <rints4 0 endl; "" <rints4 8 endl; "" <rints4 8 endl; "" <rints4 8

,lthou&h this distinction is su#tle- it's tremendously important for efficiency reasons! 'n the postfi) version of !!- since we have to return the value of the varia#le was #efore it was incremented- we'll need to make a full copy of the old version and then return it! 0ith the prefi) !!- since we're returnin& the current value of the varia#le- we can simply return a reference to it! Thus the postfi) !! can #e noticea#ly slower than the prefi) versionQ this is the reason that when advancin& an ST iterator it's faster to use the prefi) increment operator! The ne)t 5uestion we need to address is how we can le&ally use !! and -- in re&ular code! Unfortunatelyit can &et a #it complicated! 8or e)ample- the followin& code is totally le&al=
int + = 0; !!!!!!!!!!!!!!+; "" (n*rements + seven times.

This is le&al #ecause it's e5uivalent to


!!(!!(!!(!!(!!(!!(!!+))))));

The prefi) !! operator returns the varia#le #ein& incremented as an lvalue- so this statement means 4increment )- then increment ) a&ain- etc!6 /owever- if we use the postfi) version of !!- as seen here=
+!!!!!!!!!!!!!!; "" Error

0e &et a compile1time error #ecause +!! returns the ori&inal value of ) as an rvalue- which can't #e incremented #ecause that would re5uire puttin& the rvalue on the left side of an assi&nment Kin particular) Y ) + 1L! "ow- let's actually &et into some code! Unfortunately- we can't *ust sit down and write o$erator !!- since it's unclear which o$erator !! we'd #e overloadin&! C++ uses a hack to differentiate #etween the prefi) and postfi) versions of the increment operator= when overloadin& the prefi) version of !! or --- you write o$erator !! as a function that takes no parameters! To overload the postfi) version- you'll overload o$erator !!- #ut the overloaded operator will accept as a parameter the inte&er value 0! 'n code- these two declarations look like

1 @10 1
*lass :%5lass { $ubli*4 "3 ... 3" :%5lass? o$erator !!(); "" <refi+ *onst :%5lass o$erator !!(int dumm%); "" <ostfi+ $rivate4 "3 ... 3" #;

Chapter /%& :perator :verloading

"ote that the prefi) version returns a :%5lass? as an lvalue and the postfi) version a *onst :%5lass as an rvalue! 0e're allowed to implement !! and -- in any way we see fit! /owever- one of the more common tricks is to write the !! implementation as a wrapped call to o$erator !=! ,ssumin& you've provided this function- we can then write the prefi) o$erator !! as
:%5lass? :%5lass44o$erator !!() { 3this != 8; return 3this; #

,nd the postfi) o$erator !! as


*onst :%5lass :%5lass44o$erator !!(int dumm%) { :%5lass oldJalue = 3this; "" 6tore the *urrent value of the ob>e*t. !!3this; return oldJalue; #

"otice that the postfi) o$erator!! is implemented in terms of the prefi) o$erator!!! This is a fairly standard techni5ue and cuts down on the amount of code that you will need to write for the functions! 'n your future C++ career- you may encounter versions of o$erator!! that look like this=
*onst :%5lass :%5lass44o$erator !!(int) { :%5lass oldJalue = 3this; "" 6tore the *urrent value of the ob>e*t. !!3this; return oldJalue; #

,lthou&h this function takes in an int parameter- that parameter does not have a name! 't turns out that it is perfectly le&al C++ code to write functions that accept parameters #ut do not &ive names to those parameters! 'n this case- the function acts *ust like a re&ular function that accepts a parameter- e)cept that the parameter cannot #e used inside of the function! 'n the case of o$erator!!- this helps &ive a cue to readers that the inte&er parameter is not meanin&ful and e)ists solely to differentiate the prefi) and postfi) versions of the function! $;erloading 4elational $+erators Cerhaps the most commonly overloaded operators Kother than o$erator =L are the relational operatorsQ for e)ample- and ==! Unlike the assi&nment operator- #y default C++ does not provide relational operators for your o#*ects! This means that you must e)plicitly overload the == and related operators to

Chapter /%& :perator :verloading

1 @11 1

use them in code! The prototype for the relational operators looks like this Kwritten for - #ut can #e for any of the relational operatorsL=
*lass :%5lass { $ubli*4 "3 ... 3" bool o$erator $rivate4 "3 ... 3" #;

(*onst :%5lass? other) *onst;

.ou're free to choose any means for definin& what it means for one o#*ect to #e 4less than6 another! /owever- when doin& so- you must take &reat care to ensure that your less1than operator defines a total ordering on o#*ects of your type! This means that the followin& must #e true a#out the #ehavior of the less1than operator= Tric.otom/= 8or any a and b- e)actly one of a V b- a Y b- and b V a is true! Transiti;it/= 'f a V b and b V c- then a V c!

These properties of V are important #ecause they allow the notion of sorted order to make sense! 'f either of these conditions does not hold- then it is possi#le to encounter stran&e situations in which a collection of elements cannot #e put into ascendin& order! 8or e)ample- suppose that we have the followin& classwhich represents a point in two1dimensional space=
*lass <oint { $ubli*4 <oint(double +, double %); double getR() *onst; void setR(double value); double getS() *onst; void setS(double value); #

"ow consider the followin& implementation of a less1than operator for comparin& <oints=
bool o$erator (*onst <oint? one, *onst <oint? t'o) { return one.getR() t'o.getR() ?? one.getS() t'o.getS(); #

'ntuitively- this may seem like a reasona#le definition of the V operator= point a is less than point b if #oth coordinates of a are less than the correspondin& coordinates of b! /owever- this implementation of V is #ound to cause pro#lems! 'n particular- consider the followin& code=
<oint one(8, 0), t'o(0, 8); *out (one t'o) endl; *out (t'o one) endl;

/ere- we create two points called one and t'o and compare them usin& the V operator! 0hat will the first line print> Usin& the a#ove definition of o$erator - the comparison one t'o will evaluate to false #ecause the 4 coordinate of one is &reater than the 4 coordinate of t'o! 7ut what a#out t'o one> 'n this case- t'o's 4 coordinate is less than one's- #ut its y coordinate is &reater than one's! Conse5uently- we have that t'o one also evaluates to false! 0e have reached a precarious situation! 0e have found two

1 @1; 1

Chapter /%& :perator :verloading

values- one and t'o- such that one and t'o do not have e5ual values- #ut neither is less than the other! This means that we could not possi#ly sort a list of elements containin& #oth one and t'o- since neither one precedes the other! The pro#lem with the a#ove implementation of o$erator is that it violates trichotomy! Fecall from the a#ove definition of a total orderin& that trichotomy means that e)actly one of a V b- a Y b- a _ b must hold for any a and b! Gur definition of o$erator does not have this property- as illustrated a#ove! Conse5uently- we have a le&al implementation of o$erator that is wholly incorrect! 0e'll need to redefine how o$erator works in order to ensure that trichotomy holds! Gne common strate&y for implementin& o$erator is to use what's called a le4icographical ordering! To illustrate a le)ico&raphically orderin&- consider the words about and abo;e and think a#out how you would compare them alpha#etically! .ou'd #e&in #y notin& that the first letter of each word was the sameas was the second and the third! /owever- the fourth letter of the words disa&ree- and in particular the letter u from about precedes the letter ; from abo;e! Conse5uently- we would say that about comes le)ico&raphically #efore abo;e! 'nterestin&ly- thou&h- the last letter of about KtL comes after the last letter of abo;e KeL! 0e don't care- thou&h- #ecause we stopped comparin& letters as soon as we found the first mismatch in the words! This strate&y has an ele&ant analo& for ar#itrary types! 3iven a type- one way to implement o$erator is as follows! 3iven two o#*ects a and b of that type- check whether the first field of a and b are not the same! 'f so- say that a is smaller if its first field is smaller than b's first field! Gtherwise- look at the second field! 'f the fields are not the same- then return a if a's second field is smaller than b's and b otherwise! 'f notthen look at the third field- etc! To &ive you a concrete e)ample of how this works- consider the followin& revision to the <oint's o$erator function=
bool o$erator (*onst <oint? one, *onst <oint? t'o) { if (one.getR() 1= t'o.getR()) return one.getR() t'o.getR(); return one.getS() t'o.getS(); #

/ere- we first check whether the points disa&ree in their 4 coordinate! 'f so- we say that one is less than t'o only if it has a smaller 4 coordinate! Gtherwise- if the points a&ree in their 4 coordinate- then whichever has the lower y coordinate is said to have the smaller value! ,mazin&ly- this implementation strate&y results in an orderin& that is #oth trichotic and transitive- e)actly the properties we want out of the V operator! Gf course- this strate&y works on classes that have more than two fields- provided that you compare each field one at a time! 't is an interestin& e)ercise to convince yourself that a le)ico&raphical orderin& on any type o#eys trichotomy- and that such an orderin& o#eys transitivity as well! Gnce you have a workin& implementation of o$erator - it is possi#le to define all five other relational operators solely in terms of the o$erator ! This is due to the followin& set of relations=
A A P = P d d d d d d A 1(P 1(A A 1(A P A P A) P OO P P OO P P) A A)

A == P A 1= P A )= P A ) P

Chapter /%& :perator :verloading 8or e)ample- we could implement o$erator) for the <oint class as
bool o$erator) (*onst <oint? one, *onst <oint? t'o) { return t'o one; #

1 @1@ 1

0e could similarly implement o$erator = for <oints as


bool o$erator = (*onst <oint? one, *onst <oint? t'o) { return 1(one t'o); #

This is a fairly standard techni5ue- and it's well worth the effort to remem#er it! 6toring $b%ects in 6T= maps Up to this point we've avoided storin& o#*ects as keys in ST ma$s! "ow that we've covered operator overloadin&- thou&h- you have the necessary knowled&e to store o#*ects in the ST ma$ and set containers! 'nternally- the ST ma$ and set are layered on #inary trees that use the relational operators to compare elements! 2ue to some clever desi&n decisions- ST containers and al&orithms only re5uire the operator to compare two o#*ects! Thus- to store a custom class inside a ma$ or set- you simply need to overload the operator and the ST will handle the rest! 8or e)ample- here's some code to store a <oint stru*t in a ma$=
stru*t $oint; { int +, %; bool o$erator (*onst $oint;? other) *onst { if(+ 1= other.+) return + other.+; return % other.%; # #; ma$ $oint;, int) m%:a$; "" Ko' 'orBs using the default o$erator.

.ou can use a similar trick to store o#*ects as values in a set!


friend

"ormally- when you mark a class's data mem#ers private- only instances of that class are allowed to access them! /owever- in some cases you mi&ht want to allow specific other classes or functions to modify private data! 8or e)ample- if you were implementin& the ST ma$ and wanted to provide an iterator class to traverse it- you'd want that iterator to have access to the ma$'s underlyin& #inary tree! There's a sli&ht pro#lem here- thou&h! ,lthou&h the iterator is an inte&ral component of the ma$- like all other classes- the iterator cannot access private data and thus cannot traverse the tree! /ow are we to resolve this pro#lem> .our initial thou&ht mi&ht #e to make some pu#lic accessor methods that would let the iterator modify the o#*ect's internal data representation! Unfortunately- this won't work particularly well- since then any class would #e allowed to use those functions- somethin& that violates the principle of encapsulation! 'nstead- to solve this pro#lem- we can use the C++ friend keyword to &rant the iterator class access to the ma$ or set's internals! 'nside the ma$ declaration- we can write the followin&=

1 @1A 1

Chapter /%& :perator :verloading

tem$late t%$ename We%;%$e, t%$ename Jalue;%$e) *lass ma$ { $ubli*4 "3 ... 3" friend *lass iterator; *lass iterator { "3 ... iterator im$lementation here ... 3" #; #;

"ow- since iterator is a friend of ma$- it can read and modify the ma$'s private data mem#ers! $ust as we can &rant other classes friend access to a class- we can &ive friend access to &lo#al functions! 8or e)ample- if we had a free function :odif%:%5lass that accepted a :%5lass o#*ect as a reference parameter- we could let :odif%:%5lass modify the internal data of :%5lass if inside the :%5lass declaration we added the line
*lass :%5lass { $ubli*4 "3 ... 3" friend void :odif%:%5lass(:%5lass? $aram); #;

The synta) for friend can #e misleadin&! Jven thou&h we're prototypin& :odif%:%5lass inside the :%5lass function- #ecause :odif%:%5lass is a friend of :%5lass it is not a mem#er function of :%5lass! ,fter all- the purpose of the friend declaration is to &ive outside classes and functions access to the :%5lass internals! 0hen usin& friend- there are two key points to #e aware of! 8irst- the friend declaration must precede the actual implementation of the friend class or function! Since C++ compilers only make a sin&le pass over the source file- if they haven't seen a friend declaration for a function or class- when the function or class tries to modify your o#*ect's internals- the compiler will &enerate an error! Second- note that while friend is 5uite useful in some circumstances- it can 5uickly lead to code that entirely defeats the purpose of encapsulation! 7efore you &rant friend access to a piece of code- make sure that the code has a le&itimate reason to #e modifyin& your o#*ect! That is- don't make code a friend simply #ecause it's easier to write that way! Think of friend as a way of e)tendin& a class definition to include other pieces of code! The class- to&ether with all its friend code- should comprise a lo&ical unit of encapsulation! 0hen overloadin& an operator as a free function- you mi&ht want to consider &ivin& that function friend access to your class! That way- the functions can efficiently read your o#*ect's private data without havin& to &o throu&h &etters and setters! Unfortunately- friend does not interact particularly intuitively with template classes! Suppose we want to provide a friend function <`ueue&riend for a template version of the CS1067HI <`ueue! 'f <`ueue&riend is declared like this=
tem$late t%$ename ;) void <`ueue&riend(*onst <`ueue ;)? $[) { "3 ... 3" #

Chapter /%& :perator :verloading

1 @1? 1

.ou'll notice that <`ueue&riend itself is a template function! This means that when declarin& <`ueue&riend a friend of the template <`ueue- we'll need to make the friend declaration templatizedas shown here=

1 @16 1

Chapter /%& :perator :verloading

tem$late t%$ename ;) *lass <`ueue { $ubli*4 "3 ... 3" tem$late t%$ename ;) friend <`ueue&riend(*onst <`ueue ;)? $[); #;

'f you for&et the tem$late declaration- then your code will compile correctly #ut will &enerate a linker error! 0hile this can #e a #it of nuisance- it's important to remem#er since it arises fre5uently when overloadin& the stream operators- as you'll see #elow! $;erloading t.e 6tream Insertion $+erator /ave you ever wondered why *out /0ello, 'orld1/ endl is syntactically le&al> 't's throu&h P the overloaded operator in con*unction with ostreams! 'n fact- the entire streams li#rary can #e thou&ht of as a &i&antic li#rary of massively overloaded and )) operators! The C++ streams li#rary is desi&ned to &ive you ma)imum fle)i#ility with your input and output routines and even lets you define your own stream insertion and e)traction operators! This means that you are allowed to define the and )) operators so that e)pressions like *out m%5lass endl and *in )) m%5lass are well1defined! /owever- when writin& stream insertion and e)traction operators- there are hu&e num#er of considerations to keep in mind- many of which are #eyond the scope of this te)t! This ne)t section will discuss #asic strate&ies for overloadin& the operator- alon& with some limitations of the simple approach! ,s with all overloaded operators- we need to consider what the parameters and return type should #e for our overloaded operator! 7efore considerin& parameters- let's think of the return type! 0e know that it should #e le&al to chain stream insertions to&ether ( that is- code like *out 8 E endl should compile correctly! The operator associates to the left- so the a#ove code is e5ual to
(((*out 8) E) endl)R

Thus- we need the operator to return an ostream! "ow- we don't want this stream to #e *onst- since then we couldn't write code like this=
*out /;his is a string1/ set'(80) endl;

Since if *out /;his is a string1/ evaluated to a *onst o#*ect- we couldn't set the width of the ne)t operation to 10! ,lso- we cannot return the stream #y value- since stream classes have their copy functions marked private! Cuttin& these two thin&s to&ether- we see that the stream operators should return a non1*onst reference to whatever stream they're referencin&! "ow let's consider what parameters we need! 0e need to know what stream we want to write to or read from- so initially you mi&ht think that we'd define overloaded stream operators as mem#er functions that look like this=
*lass :%5lass { $ubli*4 ostream? o$erator #;

(ostream? in$ut) *onst; "" 1roblem4 7egal but in*orre*t

P ,s a reminder- the ostream class is the #ase class for output streams! This has to do with inheritance- which we'll cover in a later chapter- #ut for now *ust realize that it means that #oth stringstream and ofstream are specializations of the more &eneric ostream class!

Chapter /%& :perator :verloading Unfortunately- this isn't correct! Consider the followin& two code snippets=
*out m%5lass; m%5lass *out;

1 @1D 1

The first of these two versions makes sense- while the second is #ackwards! Unfortunately- with the a#ove definition of o$erator - we've accidentally made the second version syntactically le&al! The reason is that these two lines e)pand into calls to
*out.o$erator (m%5lass); m%5lass.o$erator (*out);

The first of these two isn't defined- since *out doesn't have a mem#er function capa#le of writin& our o#*ect Kif it did- we wouldn't need to write a stream operator in the first placeRL! /owever- #ased on our previous definition- the second version- while semantically incorrect- is syntactically le&al! Somehow we need to chan&e how we define the stream operator so that we are allowed to write *out m%5lass! To fi) this- we'll make the overloaded stream operator a free function that takes two parameters ( an ostream to write to and a m%5lass o#*ect to write! The code for this is=
ostream? o$erator (ostream? stream, *onst :%5lass? m*) { "3 ... im$lementation ... 3" return stream; #

0hile this code will work correctly- #ecause o$erator is a free function- it doesn't have access to any of the private data mem#ers of :%5lass! This can #e a nuisance- since we'd like to directly write the contents of :%5lass out to the stream without havin& to &o throu&h the Kpossi#ly inefficientL &etters and setters! Thus- we'll declare o$erator a friend inside the :%5lass declaration- as shown here=
*lass :%5lass { $ubli*4 "3 :ore fun*tions. 3" friend ostream? o$erator #;

(ostream? stream, *onst :%5lass? m*);

"ow- we're all set to do readin& and writin& inside the #ody of the insertion operator! 't's not particularly difficult to write the stream insertion operator ( all that we need to do is print out all of the meanin&ful class information with some formattin& information! So- for e)ample- &iven a <oint class representin& a point in ;12 space- we could write the insertion operator as
ostream? o$erator stream A(A return stream; # (ostream? stream, *onst <oint? $t) { $t.+ /, / $t.% A)A;

0hile this code will work in most cases- there are a few spots where it *ust won't work correctly! 8or e)ample- suppose we write the followin& code=
*out *out /08ECGHNDFM08ECGHNDFM/ endl; "" ;o see the number of *hara*ters. set'(E0) m%<oint endl;

ookin& at this code- you'd e)pect that it would cause m%<oint to #e printed out and padded with space characters until it is at least twenty characters wide! Unfortunately- this isn't what happens! Since o$erator writes the o#*ect one piece at a time- the output will look somethin& like this=

1 @1E 1
01(3)*+ ,-01(3)*+ ,300 )4

Chapter /%& :perator :verloading

That's nineteen spaces- followed #y the actual <oint data! The pro#lem is that when we invoke o$erator - the function writes a sin&le ( character to stream! 't's this operation- not the 0oint as a whole- that will &et ali&ned to ;0 characters! There are many ways to circumvent this pro#lem- #ut perhaps the simplest is to #uffer the output into a stringstream and then write the contents of the stringstream to the destination in a sin&le operation! This can &et a #it complicated- especially since you'll need to copy the stream formattin& information over! 0ritin& a correct stream e)traction operator K o$erator ))L is complicated! 8or more information on writin& stream e)traction operators- consult a reference! $;erloading G and -: Consider the followin& code snippet=
for(set string)44iterator itr = m%6et.begin(); itr 1= m%6et.end(); !!itr) *out 3itr / has length / itr-)length() endl;

/ere- we traverse a set string) usin& iterators- printin& out each strin& and its len&th! 'nterestin&lyeven thou&h set iterators are not raw pointers Kthey're o#*ects capa#le of traversin& #inary treesL- thanks to operator overloadin&- they can respond to the 3 and -) operators as thou&h they were re&ular C++ pointers! 'f you create a custom class that acts like a C++ pointer Kperhaps a custom iterator or 4smart pointer-6 a topic we'll return to laterL- you can provide implementations of the pointer dereference and mem#er selection operators 3 and -) #y overloadin& their respective operator functions! The simpler of these two functions is the pointer dereference operator! To make an o#*ect that can #e dereferenced to yield an o#*ect of type ;- the synta) for its 3 operator is
*lass <ointer5lass { $ubli*4 ;? o$erator 3() *onst; "3 ... 3" #;

.ou can invoke the o$erator 3 function #y 4dereferencin&6 the custom pointer o#*ect! 8or e)ample- the followin& code=
3m%5ustom<ointer = 8CD;

is completely e5uivalent to
m%5ustom<ointer.o$erator 3() = 8CD;

7ecause we can assi&n a value to the result of o$erator 3- the o$erator 3 function should return an lvalue Ka non1*onst referenceL! There are two other points worth notin& here! 8irst- how can C++ distin&uish this o$erator 3 for pointer dereference from the o$erator 3 used for multiplication> The answer has to do with the num#er of parameters to the function! Since a pointer dereference is a unary operator- the function prototype for the pointer1dereferencin& o$erator 3 takes no parameters! /ad we wanted to write o$erator 3 for

Chapter /%& :perator :verloading

1 @1< 1

multiplication- we would have written a function o$erator 3 that accepts a parameter Kor a free function acceptin& two parametersL! Second- why is o$erator 3 marked *onst> This has to do with the difference #etween *onst pointers and pointers1to1*onst! Suppose that we have a *onst instance of a custom pointer class! Since the pointer ob!ect is *onst- it acts as thou&h it is a *onst pointer rather than a pointer1to1*onst! Conse5uently- we should #e a#le to dereference the o#*ect and modify its stored pointer without affectin& its *onstness! The arrow operator o$erator -) is sli&htly more complicated than o$erator 3! 'nitially- you mi&ht think that o$erator -) would #e a #inary operator- since you use the arrow operator in statements like m%5lass<tr-)m%Element! /owever- C++ has a rather clever mechanism for o$erator -) that makes it a unary operator! , class's o$erator -) function should return a pointer to the o#*ect that the arrow operator should actually #e applied to! This may #e a #it confusin&- so an e)ample is in order! Suppose we have a class 5ustom6tring<ointer that acts as thou&h it's a pointer to a C++ string o#*ect! Then if we have the followin& code=
5ustom6tring<ointer m%5ustom<ointer; *out m%5ustom<ointer-)length() endl;

This code is e5uivalent to


5ustom6tring<ointer m%5ustom<ointer; *out (m%5ustom<ointer.o$erator -)())-)length() endl;

'n the first version of the code- we treated the m%5ustom<ointer o#*ect as thou&h it was a real pointer #y usin& the arrow operator to select the length function! This code e)pands out into two smaller steps= 1. The 5ustom6tring<ointer's o$erator -) function is called to determine which pointer the arrow should #e applied to! 2. The returned pointer then has the -) operator applied to select the length function! Thus when writin& the o$erator -) function- you simply need to return the pointer that the arrow operator should #e applied to! 'f you're writin& a custom iterator class- for e)ample- this is pro#a#ly the element #ein& iterator over! 0e'll e)plore one e)ample of overloadin& these operators in a later chapter! =ist of $;erloadable $+erators The followin& ta#le lists the most commonly1used operators you're le&ally allowed to overload in C++alon& with any restrictions a#out how you should define the operator!
Operator
=

Yie !s Bval#e

"sage
:%5lass? o$erator =(*onst :%5lass? other);

See the the earlier chapter for details!


!= -= 3= "= \= (etc.)

Bval#e

:%5lass? o$erator !=(*onst :%5lass? other);

0hen writin& compound assi&nment operators- make sure that you correctly handle 4self1compound1assi&nment!6

1 @;0 1
! - 3 " \ (etc.)

Chapter /%& :perator :verloading


<val#e
*onst :%5lass o$erator ! (*onst :%5lass? one, *onst :%5lass? t'o);

These operator should #e defined as a free functions!


= == ) )= 1=

<val#e

bool o$erator bool o$erator

(*onst :%5lass? other) *onst; (*onst :%5lass? one, *onst :%5lass? t'o);

'f you're plannin& to use relational operators only for the ST container classesyou *ust need to overload the operator! Gtherwise- you should overload all si) so that users aren't surprised that one 1= t'o is ille&al while 1(one == t'o) is defined!
[]

Bval#e

Elem;%$e? o$erator [](*onst We%;%$e? Be%); *onst Elem;%$e? o$erator [](*onst We%;%$e? Be%) *onst;

Bost of the time you'll need a *onst1overloaded version of the #racket operator! 8or&ettin& to provide one can lead to a real headacheR
!! -3

Pre*i4F Bval#e Post*i4F <val#e <val#e Bval#e

Crefi) version= :%5lass? o$erator !!(); Costfi) version= *onst :%5lass o$erator !!(int dumm%);
*onst :%5lass o$erator -() *onst; Elem;%$e? o$erator 3() *onst;

0ith this function- you're allowin& your class to act as thou&h it's a pointer! The return type should #e a reference to the o#*ect it's 4pointin&6 at! This is how the ST iterators and smart pointers work! "ote that this is the unary 3 operator and is not the same as the 3 multiplicative operator!
-)

Bval#e

Elem;%$e3 o$erator -)() *onst;

'f the -) is overloaded for a class- whenever you write m%5lass-)m%:ember- it's e5uivalent to m%5lass.o$erator -)()-)m%:ember! "ote that the function should #e *onst even thou&h the o#*ect returned can still modify data! This has to do with how pointers can le&ally #e used in C++! 8or more information- refer to the chapter on *onst!
))

Bval#e

friend ostream? o$erator

(ostream? out, *onst :%5lass? m*); friend istream? o$erator )) (istream? in, :%5lass? m*);

()

Naries

See the chapter on functors!

#xten!e! #xamp e: grid The %TB encompasses a wide selection o* associative and seE#ence containers. However, one #se*#l data type that did not *ind its way into the %TB is a m#ltidimensional array class a0in to the "%10!&'( Grid. 2n this e4tended e4ample, we will implement an %TB)*riendly version o* the "%10!&'( Grid class, which we.ll call grid, that will s#pport %TB)compatible iterators, int#itive element)access synta4, and relational operators. 3nce we.re done, we.ll have an ind#strial)stren/th container class we will #se later in this boo0 to implement more comple4 e4amples. 'mplementin& a fully1functional grid may seem dauntin& at first- #ut fortunately it's easy to #reak the work up into several smaller steps that culminate in a workin& class!

Chapter /%& :perator :verloading 6te+ -8 Im+lement t.e Basic grid Class.

1 @;1 1

7efore divin& into some of the grid's more advanced features- we'll #e&in #y implementin& the grid #asics! 7elow is a partial specification of the grid class that provides core functionality= Figure %& Iasic 5incomplete6 inter$ace $or the grid class
tem$late t%$ename ;) *lass grid { $ubli*4 "3 5onstru*tors, destru*tors. 3" grid(); grid(siUeLt ro's, siUeLt *ols);

"" 5reate em$t% grid "" 5onstru*t to s$e*ified siUe

"3 IesiUing o$erations. 3" void *lear(); "" Em$t% the grid void resiUe(siUeLt ro's, siUeLt *ols); "" IesiUe the grid "3 `uer% o$erations. 3" siUeLt numIo's() *onst; siUeLt num5ols() *onst; bool em$t%() *onst; siUeLt siUe() *onst; "" "" "" "" Ieturns Ieturns Ieturns Ieturns number of ro's in the grid number of *olumns in the grid 'hether the grid is em$t% the number of elements

"3 Element a**ess. 3" ;? getAt(siUeLt ro', int *ol); "" A**ess individual elements *onst ;? getAt(int ro', int *ol) *onst; "" 6ame, but *onst #;

These functions are defined in &reater detail here=


grid34E grid3si6e8t rows0 si6e8t cols4E

Constructs a new- empty grid! Constructs a new grid with the specified num#er of rows and columns! Jach element in the grid is initialized to its default value! Fesizes the grid to 0)0! 2iscards the current contents of the grid and resizes the grid to the specified size! Jach element in the grid is initialized to its default value! Feturns the num#er of rows and columns in the grid! Feturns whether the grid contains no elements! This is true if either the num#er of rows or columns is zero! Feturns the num#er of total elements in the grid! Feturns a reference to the element at the specified position! This function is *onst-overloaded! 0e won't worry a#out the case where the indices are out of #ounds!

#oid clear34E #oid resi6e3si6e8t rows0 si6e8t cols4E

si6e8t numBows34 constE si6e8t numHols34 constE bool empty34 constE

si6e8t si6e34 constE %P get.t3si6e8t row0 si6e8t col4E const %P get.t3si6e8t row0 si6e8t col4 constE

7ecause grids can #e dynamically resized- we will need to #ack grid with some sort of dynamic memory mana&ement! 7ecause the grid represents a two1dimensional entity- you mi&ht think that we need to use

1 @;; 1

Chapter /%& :perator :verloading

a dynamically1allocated multidimensional array to store grid elements! /owever- workin& with dynamically1allocated multidimensional arrays is tricky and &reatly complicates the implementation! 8ortunately- we can sidestep this pro#lem #y implementin& the two1dimensional grid o#*ect usin& a sin&le1dimensional array! To see how this works- consider the followin& @)@ &rid= 0 @ 6 1 A D ; ? E

0e can represent all of the elements in this &rid usin& a one1dimensional array #y layin& out all of the elements se5uentially- as seen here= 0 1 ; @ A ? 6 D E

'f you'll notice- in this orderin&- the three elements of the first row appear in order as the first three elements- then the three elements of the second row in order- and finally the three elements of the final row in order! 7ecause this one1dimensional representation of a two1dimensional o#*ect preserves the orderin& of individual rows- it is sometimes referred to as row"ma!or order! To represent a &rid in row1ma*or order- we need to #e a#le to convert #etween &rid coordinates and array indices! 3iven a coordinate Krow- colL in a &rid of dimensions K nrows- ncolsL- the correspondin& position in the row1ma*or order representation of that &rid is &iven #y inde4 S col + row K ncols! The intuition #ehind this formula is that #ecause the orderin& within any row is preserved- each horizontal step in the &rid translates into a sin&le step forward or #ackward in the row1ma*or order representation of the &rid! /owever- each vertical step in the &rid re5uires us to advance forward to the ne)t row in the linearized &rid- skippin& over ncols elements! Usin& row1ma*or order- we can #ack the grid class with a re&ular ST ve*tor- as shown here=
tem$late t%$ename ;) *lass grid { $ubli*4 grid(); grid(siUeLt ro's, siUeLt *ols); void *lear(); void resiUe(siUeLt ro's, siUeLt *ols); siUeLt numIo's() *onst; siUeLt num5ols() *onst; bool em$t%() *onst; siUeLt siUe() *onst; ;? getAt(siUeLt ro', siUeLt *ol); *onst ;? getAt(siUeLt ro', siUeLt *ol) *onst; $rivate4 ve*tor ;) elems; siUeLt ro's; siUeLt *ols; #;

Chapter /%& :perator :verloading

1 @;@ 1

Serendipitously- implementin& the grid with a ve*tor allows us to use C++'s automatically1&enerated copy constructor and assi&nment operator for grid! Since ve*tor already mana&es its own memory- we don't need to handle it manually! "ote that we e)plicitly keep track of the num#er of rows and columns in the grid even thou&h the ve*tor stores the total num#er of elements! This is necessary so that we can compute indices in the row1ma*or orderin& for points in two1dimensional space! The a#ove functions have relatively strai&htforward implementations that are &iven #elow=
tem$late # tem$late t%$ename ;) grid ;)44grid(siUeLt ro's, siUeLt *ols) 4 elems(ro's 3 *ols), ro's(ro's), *ols(*ols) { # tem$late t%$ename ;) void grid ;)44*lear() { resiUe(0, 0); # tem$late t%$ename ;) void grid ;)44resiUe(siUeLt ro's, siUeLt *ols) { "3 6ee belo' for assign 3" elems.assign(ro's 3 *ols, Elem;%$e()); "3 E+$li*it this-) re[uired sin*e $arameters have same name as members. 3" this-)ro's = ro's; this-)*ols = *ols; # tem$late t%$ename ;) siUeLt grid ;)44numIo's() *onst { return ro's; # tem$late t%$ename ;) siUeLt grid ;)44num5ols() *onst { return *ols; # tem$late t%$ename ;) bool grid ;)44em$t%() *onst { return siUe() == 0; # tem$late t%$ename ;) siUeLt grid ;)44siUe() *onst { return numIo's() 3 num5ols(); # "3 @se ro'-ma>or ordering to a**ess the $ro$er element of the ve*tor. 3" tem$late t%$ename ;) ;? grid ;)44getAt(siUeLt ro', siUeLt *ol) { return elems[*ol ! ro' 3 *ols]; # tem$late t%$ename ;) *onst ;? grid ;)44getAt(siUeLt ro',siUeLt *ol) *onst { return elems[*ol ! ro' 3 *ols]; # t%$ename ;) grid ;)44grid() 4 ro's(0), *ols(0) {

1 @;A 1

Chapter /%& :perator :verloading

Bost of these functions are one1liners and are e)plained in the comments! The only function that you may find interestin& is resiUe- which uses the ve*tor's assign mem#er function! assign is similar to resiUe in that it chan&es the size of the ve*tor- #ut unlike resiUe assign discards all of the current ve*tor contents and replaces them with the specified num#er of copies of the specified element! The use of Elem;%$e() as the second parameter to assign means that we will fill the ve*tor with copies of the default value of the type #ein& stored Ksince Elem;%$e() uses the temporary o#*ect synta) to create a new Elem;%$eL! 6te+ 18 Add 6u++ort for Iterators "ow that we have the #asics of a grid class- it's time to add iterator support! This will allow us to plu& the grid directly into the ST al&orithms and will #e invalua#le in a later chapter! ike the ma$ and set- the grid does not naturally lend itself to a linear traversal ( after all- grid is two1 dimensional ( and so we must ar#itrarily choose an order in which to visit elements! Since we've implemented the grid in row1ma*or order- we'll have grid iterators traverse the &rid row1#y1row- top to #ottom- from left to ri&ht! Thus- &iven a @)A grid- the order of the traversal would #e 0 @ 6 < 1 A D 10 ; ? E 11

This order of iteration maps naturally onto the row1ma*or orderin& we've chosen for the grid! 'f we consider how the a#ove &rid would #e laid out in row1ma*or order- the resultin& array would look like this= 0 1 ; @ A ? 6 D E < 10 11

Thus this iteration scheme maps to a simple linear traversal of the underlyin& representation of the grid! 7ecause we've chosen to represent the elements of the grid usin& a ve*tor- we can iterate over the elements of the grid usin& ve*tor iterators! 0e thus add the followin& definitions to the grid class=

Chapter /%& :perator :verloading


tem$late t%$ename ;) *lass grid { $ubli*4 grid(); grid(siUeLt ro's, siUeLt *ols); void *lear(); void resiUe(siUeLt ro's, siUeLt *ols); siUeLt numIo's() *onst; siUeLt num5ols() *onst; bool em$t%() *onst; siUeLt siUe() *onst; ;? getAt(siUeLt ro', siUeLt *ol); *onst ;? getAt(siUeLt ro', siUeLt *ol) *onst; t%$edef t%$ename ve*tor ;)44iterator iterator; t%$edef t%$ename ve*tor ;)44*onstLiterator *onstLiterator; $rivate4 ve*tor ;) elems; siUeLt ro's; siUeLt *ols; #;

1 @;? 1

"ow- clients of grid can create grid int)44iterators rather than ve*tor int)44iterators! This makes the interface more intuitive and increases encapsulationQ since iterator is a t%$edef- if we later decide to replace the underlyin& representation with a dynamically1allocated array- we can chan&e the t%$edefs to
t%$edef Elem;%$e3 iterator; t%$edef *onst Elem;%$e3 *onstLiterator;

,nd clients of the grid will not notice any difference! "otice that in the a#ove t%$edefs we had to use the t%$ename keyword to name the type ve*tor Elem;%$e)44iterator! This is the pesky ed&e case mentioned in the chapter on templates and somehow mana&es to creep into more than its fair share of code! Since iterator is a nested type inside the template type ve*tor Elem;%$e)- we have to use the t%$ename keyword to indicate that iterator is the name of a type rather than a class constant! 0e've now defined an iterator type for our grid- so what functions should we e)port to the grid clients> 0e'll at least want to provide support for begin and end- as shown here=

1 @;6 1
tem$late t%$ename ;) *lass grid { $ubli*4 grid(); grid(siUeLt ro's, siUeLt *ols); void *lear(); void resiUe(siUeLt ro's, siUeLt *ols); siUeLt numIo's() *onst; siUeLt num5ols() *onst; bool em$t%() *onst; siUeLt siUe() *onst; ;? getAt(siUeLt ro', siUeLt *ol); *onst ;? getAt(siUeLt ro', siUeLt *ol) *onst;

Chapter /%& :perator :verloading

t%$edef t%$ename ve*tor ;)44iterator iterator; t%$edef t%$ename ve*tor ;)44*onstLiterator *onstLiterator; iterator begin(); *onstLiterator begin() *onst; iterator end(); *onstLiterator end() *onst; $rivate4 ve*tor ;) elems; siUeLt ro's; siUeLt *ols; #;

0e've provided two versions of each function so that clients of a *onst grid can still use iterators! These functions are easily implemented #y returnin& the value of the underlyin& ve*tor's begin and end functions- as shown here=
tem$late t%$ename ;) t%$ename grid ;)44iterator grid ;)44begin() { return elems.begin(); #

"otice that the return type of this function is t%$ename grid Elem;%$e)44iterator rather than *ust iterator! 7ecause iterator is a nested type inside grid- we need to use grid Elem;%$e)44iterator to specify which iterator we want- and since grid is a template type we have to use the t%$ename keyword to indicate that iterator is a nested type! Gtherwise- this function should #e strai&htforward! The rest of the functions are implemented here=
tem$late t%$ename ;) t%$ename grid ;)44*onstLiterator grid ;)44begin() *onst { return elems.begin(); # tem$late t%$ename ;) t%$ename grid ;)44iterator grid ;)44end() { return elems.end(); # tem$late t%$ename ;) t%$ename grid ;)44*onstLiterator grid ;)44end() *onst { return elems.end(); #

Chapter /%& :perator :verloading

1 @;D 1

7ecause the grid is implemented in row1ma*or order- elements of a sin&le row occupy consecutive locations in the ve*tor! 't's therefore possi#le to return iterators delineatin& the start and end of each row in the grid! This is useful functionality- so we'll provide it to clients of the grid throu&h a pair of mem#er functions ro'Lbegin and ro'Lend Kplus *onst overloadsL! These functions are declared here=
tem$late t%$ename ;) *lass grid { $ubli*4 grid(); grid(siUeLt ro's, siUeLt *ols); void *lear(); void resiUe(siUeLt ro's, siUeLt *ols); siUeLt numIo's() *onst; siUeLt num5ols() *onst; bool em$t%() *onst; siUeLt siUe() *onst; ;? getAt(siUeLt ro', siUeLt *ol); *onst ;? getAt(siUeLt ro', siUeLt *ol) *onst; t%$edef t%$ename ve*tor Elem;%$e)44iterator iterator; t%$edef t%$ename ve*tor Elem;%$e)44*onstLiterator *onstLiterator; iterator *onstLiterator iterator *onstLiterator iterator *onstLiterator iterator *onstLiterator begin(); begin() *onst; end(); end() *onst; ro'Lbegin(siUeLt ro'); ro'Lbegin(siUeLt ro') *onst; ro'Lend(siUeLt ro'); ro'Lend(siUeLt ro') *onst;

$rivate4 ve*tor ;) elems; siUeLt ro's; siUeLt *ols; ^Q

7efore implementin& these functions- let's take a minute to fi&ure out e)actly where the iterations we return should point to! Fecall that the element at position K row- 0L in a &rid of size K rows- colsL can #e found at position row P cols! 0e should therefore have ro'Lbegin(ro') return an iterator to the ro' P cols element of the ve*tor! Since there are cols elements in each row and ro'Lend should return an iterator to one position past the end of the row- this function should return an iterator to the position cols past the location returned #y ro'Lbegin! 3iven this information- we can implement these functions as shown here=
tem$late t%$ename ;) t%$ename grid ;)44iterator grid ;)44ro'Lbegin(int ro') { return begin() ! num5ols() 3 ro'; # tem$late t%$ename ;) t%$ename grid ;)44*onstLiterator grid ;)44ro'Lbegin(int ro') *onst { return begin() ! num5ols() 3 ro'; #

1 @;E 1

Chapter /%& :perator :verloading

tem$late t%$ename ;) t%$ename grid ;)44iterator grid ;)44ro'Lend(int ro') { return ro'Lbegin(ro') ! num5ols(); # tem$late t%$ename ;) t%$ename grid ;)44*onstLiterator grid ;)44ro'Lend(int ro') *onst { return ro'Lbegin(ro') ! num5ols(); #

0e now have an ele&ant iterator interface for the grid class! 0e can iterate over the entire container as a whole- *ust one row at a time- or some com#ination thereof! This ena#les us to interface the grid with the ST al&orithms! 8or e)ample- to zero out a grid int)- we can use the fill al&orithm- as shown here=
fill(m%Grid.begin(), m%Grid.end(), 0);

0e can also sort the elements of a row usin& sort=


sort(m%Grid.ro'Lbegin(0), m%Grid.ro'Lend(0));

0ith only a handful of functions we're now capa#le of plu&&in& directly into the full power of the al&orithms! This is part of the #eauty of the ST ( had the al&orithms #een desi&ned to work on containers rather than iterator ran&es- this would not have #een possi#le! 6te+ 28 Add 6u++ort for t.e )lement 6election $+erator 0hen usin& re&ular C++ multidimensional arrays- we can write code that looks like this=
int m%Arra%[8CD][GE]; m%Arra%[E][G] = ED8FEF; m%Arra%[M][0] = C8G8HM;

/owever- with the current specification of the grid class- the a#ove code would #e ille&al if we replaced the multidimensional array with a grid int)- since we haven't provided an implementation of o$erator []! ,ddin& support for element selection to linear classes like the ve*tor is simple ( we simply have the #rackets operator return a reference to the proper element! Unfortunately- it is much trickier to desi&n grid such that the #racket synta) works correctly! The reason is that if we write code that looks like this=
grid int) m%Grid(8CD, GE); int value = m%Grid[E][G];

7y replacin& the #racket synta) with calls to o$erator []- we see that this code e)pands out to
grid int) m%Grid(8CD, GE); int value = (m%Grid.o$erator[] (E)).o$erator[] (G);

/ere- there are two calls to o$erator []- one invoked on m%Grid and the other on the value returned #y m%Grid.o$erator[](E)! To make the a#ove code compile- the o#*ect returned #y the grid's o$erator[] must itsel$ define an o$erator [] function! 't is this returned o#*ect- rather than the grid itself- which is responsi#le for retrievin& the re5uested element from the grid! Since this temporary o#*ect is used to perform a task normally reserved for the grid- it is sometimes known as a pro4y ob!ect !

Chapter /%& :perator :verloading

1 @;< 1

/ow can we implement the grid's o$erator [] so that it works as descri#ed a#ove> 8irst- we will need to define a new class representin& the o#*ect returned #y the grid's o$erator []! 'n this discussionwe'll call it :utableIeferen*e- since it represents an o#*ect that can call #ack into the grid and mutate it! 8or simplicity and to ma)imize encapsulation- we'll define :utableIeferen*e inside of grid! This results in the followin& interface for grid=
tem$late t%$ename ;) *lass grid { $ubli*4 "3 ... $reviousl%-defined fun*tions ... 3" *lass :utableIeferen*e { $ubli*4 friend *lass grid; ;? o$erator[] (siUeLt *ol); $rivate4 :utableIeferen*e(grid3 o'ner, siUeLt ro'); grid3 *onst o'ner; *onst siUeLt ro';

#;

$rivate4 ve*tor ;) elems; siUeLt ro's; siUeLt *ols; #;

The :utableIeferen*e o#*ect stores some a pointer to the grid that created it- alon& with the inde) passed in to the grid's o$erator [] function when the :utableIeferen*e was created! That waywhen we invoke the :utableIeferen*e's o$erator [] function specifyin& the col coordinate of the &ridwe can pair it with the stored row coordinate- then 5uery the grid for the element at K row- colL! 0e have also made grid a friend of :utableIeferen*e so that the grid can call the private constructor necessary to initialize a :utableIeferen*e! 0e can implement :utableIeferen*e as follows=
tem$late t%$ename ;) grid ;)44:utableIeferen*e44:utableIeferen*e(grid3 o'ner, int ro') 4 o'ner(o'ner), ro'(ro') { # tem$late t%$ename ;) ;? grid ;)44:utableIeferen*e44o$erator[] (int *ol) { return o'ner-)getAt(ro', *ol); #

"otice that #ecause :utableIeferen*e is a nested class inside grid- the implementation of the :utableIeferen*e functions is prefaced with grid Elem;%$e)44:utableIeferen*e instead of *ust :utableIeferen*e! /owever- in this particular case the pesky t%$ename keyword is not necessary #ecause we are prototypin& a function inside :utableIeferen*e rather than usin& the type :utableIeferen*e in an e)pression! "ow that we've implemented :utableIeferen*e- we'll define an o$erator [] function for the grid class that constructs and returns a properly1initialized :utableIeferen*e! This function accepts an row

1 @@0 1

Chapter /%& :perator :verloading

coordinate- and returns a :utableIeferen*e storin& that row num#er and a pointer #ack to the grid! That way- if we write
int value = m%Grid[8][E];

The followin& se5uences of actions occurs= 1. m%Grid.o$erator[] is invoked with the parameter 1! 2. m%Grid.o$erator[] creates a :utableIeferen*e storin& the row coordinate 1 and a means for communicatin& #ack with the m%Grid o#*ect! 3. m%Grid.o$erator[] returns this :utableIeferen*e! 4. The returned :utableIeferen*e then has its o$erator[] function called with parameter ;! . The returned :utableIeferen*e then calls #ack to the m%Grid o#*ect and asks for the element at position K1- ;L! This se5uence of actions is admittedly comple)- #ut is transparent to the client of the grid class and runs efficiently!
o$erator[] is defined and implemented as follows= tem$late t%$ename ;) *lass grid { $ubli*4 "3 ... $reviousl%-defined fun*tions ... 3" *lass :utableIeferen*e { $ubli*4 friend *lass grid; ;? o$erator[] (siUeLt *ol); $rivate4 :utableIeferen*e(grid3 o'ner, siUeLt ro'); grid3 *onst o'ner; *onst siUeLt ro';

#; :utableIeferen*e o$erator[] (int ro'); $rivate4 ve*tor ;) elems; siUeLt ro's; siUeLt *ols; #; tem$late t%$ename ;) t%$ename grid ;)44:utableIeferen*e grid ;)44o$erator[] (int ro') { return :utableIeferen*e(this, ro'); #

"otice that we've only provided an implementation of the non1 *onst version of o$erator[]! 7ut what if we want to use o$erator[] on a *onst grid> 0e would similarly need to return a pro)y o#*ect- #ut that o#*ect would need to &uarantee that grid clients could not write code like this=

Chapter /%& :perator :verloading


*onst grid int) m%Grid(8CD, GE); m%Grid[0][0] = ED8F; "" =oo$s1 :odified *onst ob>e*t1

1 @@1 1

To prevent this sort of pro#lem- we'll have the *onst version of o$erator[] return a pro)y o#*ect of a different type- called (mmutableIeferen*e which #ehaves similarly to :utableIeferen*e #ut which returns *onst references to the elements in the grid! This results in the followin& interface for grid=
tem$late t%$ename ;) *lass grid { $ubli*4 "3 ... $reviousl%-defined fun*tions ... 3" *lass :utableIeferen*e { $ubli*4 friend *lass grid; ;? o$erator[] (siUeLt *ol); $rivate4 :utableIeferen*e(grid3 o'ner, siUeLt ro'); grid3 *onst o'ner; *onst siUeLt ro';

#; :utableIeferen*e o$erator[] (int ro'); *lass (mmutableIeferen*e { $ubli*4 friend *lass grid; *onst ;? o$erator[] (siUeLt *ol) *onst; $rivate4 :utableIeferen*e(*onst grid3 o'ner, siUeLt ro'); *onst grid3 *onst o'ner; *onst siUeLt ro'; #; (mmutableIeferen*e o$erator[] (siUeLt ro') *onst; $rivate4 ve*tor ;) elems; siUeLt ro's; siUeLt *ols; #; (mmutableIeferen*e and the *onst version of o$erator[] are similar to :utableIeferen*e and the non1*onst version of o$erator[]- and to save space we won't write it here! The complete listin& of the grid class at the end of this chapter contains the implementation if you're interested!

6te+ 38 Define 4elational $+erators "ow that our grid has full support for iterators and a nice #racket synta) that lets us access individual elements- it's time to put on the finishin& touches! ,s a final step in the pro*ect- we'll provide implementations of the relational operators for our grid class! 0e #e&in #y updatin& the grid interface to include the followin& functions=

1 @@; 1
tem$late t%$ename ;) *lass grid { $ubli*4 "3 ... $reviousl%-defined fun*tions ... 3" bool bool bool bool bool bool o$erator o$erator o$erator o$erator o$erator o$erator = == 1= )= ) (*onst (*onst (*onst (*onst (*onst (*onst grid? grid? grid? grid? grid? grid? other) other) other) other) other) other) *onst; *onst; *onst; *onst; *onst; *onst;

Chapter /%& :perator :verloading

$rivate4 ve*tor ;) elems; siUeLt ro's; siUeLt *ols; #;

"ote that of the si) operators listed a#ove- only the == and 1= operators have intuitive meanin&s when applied to grids! /owever- it also makes sense to define a operator over grids so that we can store them in ST ma$ and set containers- and to ensure consistency- we should define the other three operators as well! 7ecause there is no natural interpretation for what it means for one grid to #e 4less than6 another- we are free to implement these functions in any way that we see fit- provided that we o#ey transitivity and trichotomy! ,s mentioned earlier it is possi#le to implement all si) of the relational operators in terms of the less1than operator! Gne strate&y for implementin& the relational operators is thus to implement *ust the less1than operator and then to define the other five as wrapped calls to o$erator ! 7ut what is the #est way to determine whether one grid compares less than another> Gne &eneral approach is to define a le4icographical ordering over grids! 0e will compare each field one at a time- checkin& to see if the fields are e5ual! 'f so- we move on to the ne)t field! Gtherwise- we immediately return that one grid is less than another without lookin& at the remainin& fields! 'f we &o throu&h every field and find that the grids are e5ual- then we can return that neither &rid is less than the other! This is similar to the way that we mi&ht order words alpha#etically ( we find the first mismatched character- then return which word compares first! 0e can #e&in #y implementin& o$erator as follows=
tem$late t%$ename ;) bool grid ;)44o$erator (*onst grid? other) *onst { "3 5om$are the number of ro's and return if thereAs a mismat*h. 3" if(ro's 1= other.ro's) return ro's other.ro's; "3 Ke+t *om$are the number of *olumns the same 'a%. 3" if(*ols 1= other.*ols) return *ols other.*ols; "3 ... 3" #

/ere- we compare the ro's fields of the two o#*ects and immediately return if they aren't e5ual! 0e can then check the *ols fields in the same way! 8inally- if the two grids have the same num#er of rows and columns- we need to check how the elements of the grids compare! 8ortunately- this is strai&htforward thanks to the ST le+i*ogra$hi*alL*om$are al&orithm! le+i*ogra$hi*alL*om$are accepts four iterators delineatin& two ran&es- then le)ico&raphically compares the elements in those ran&es and returns if the first ran&e compares le)ico&raphically less than the second! Usin& le+i*ogra$hi*alL*om$are- we can finish our implementation of o$erator as follows=

Chapter /%& :perator :verloading


tem$late t%$ename ;) bool grid ;)44o$erator (*onst grid? other) *onst { "3 5om$are the number of ro's and return if thereAs a mismat*h. 3" if(ro's 1= other.ro's) return ro's other.ro's; "3 Ke+t *om$are the number of *olumns the same 'a%. 3" if(*ols 1= other.*ols) return *ols other.*ols;

1 @@@ 1

return le+i*ogra$hi*alL*om$are(begin(), end(), other.begin(), other.end()); #

,ll that's left to do now is to implement the other five relational operators in terms of o$erator done #elow=

! This is

tem$late t%$ename ;) bool grid ;)44o$erator )=(*onst grid? other) *onst { return 1(3this other); # tem$late t%$ename ;) bool grid ;)44o$erator ==(*onst grid? other) *onst { return 1(3this other) ?? 1(other 3this); # tem$late t%$ename ;) bool grid ;)44o$erator 1=(*onst grid? other) *onst { return (3this other) OO (other 3this); # tem$late t%$ename ;) bool grid ;)44o$erator ) (*onst grid? other) *onst { return other 3this; # tem$late t%$ename ;) bool grid ;)44o$erator return 1(other 3this); # =(*onst grid? other) *onst {

,t this point we're doneR 0e now have a complete workin& implementation of the grid class that supports iteration- element access- and the relational operators! To #oot- it's implemented on top of the ve*tor- meanin& that it's slick and efficient! This class should #e your one1stop solution for applications that re5uire a two1dimensional array!

1 @@A 1 (ore to )*+lore

Chapter /%& :perator :verloading

Gperator overloadin& is an enormous topic in C++ and there's simply not enou&h space to cover it all in this chapter! 'f you're interested in some more advanced topics- consider readin& into the followin&= 1. $;erloaded new and delete= .ou are allowed to overload the ne' and delete operators- in case you want to chan&e how memory is allocated for your class! "ote that the overloaded ne' and delete operators simply chan&e how memory is allocated- not what it means to write ne' :%5lass! Gverloadin& ne' and delete is a complicated task and re5uires a solid understandin& of how C++ memory mana&ement works- so #e sure to consult a reference for details! 2. Con;ersion functions= 'n an earlier chapter- we covered how to write conversion constructorsfunctions that convert o#*ects of other types into instances of your new class! /owever- it's possi#le to use operator overloadin& to define an implicit conversion from o#*ects of your class into o#*ects of other types! The synta) is o$erator ;%$e()- where ;%$e is the data type to convert your o#*ect to! Bany professional pro&rammers advise a&ainst conversion functions- so make sure that they're really the #est option #efore proceedin&! !ractice !roblems Gperator overloadin& is 5uite difficult #ecause your functions must act as thou&h they're the #uilt1in operators! /ere are some practice pro#lems to &et you used to overloadin& operators= 1. 0hat is an overloaded operator> 2. 0hat is an lvalue> ,n rvalue> 2oes the ! operator yield an lvalue or an rvalue> /ow a#out the pointer dereference operator> 3. ,re overloaded operators inherently more efficient than re&ular functions> 4. J)plain how to implement o$erator ! in terms of o$erator !=! . 0hat is the si&nature of an overloaded operator for su#traction> 8or unary ne&ation> !. /ow do you differentiate #etween the prefi) and postfi) versions of the !! operator> $. 0hat does the -) operator return> 6. 0hat is a friend function> /ow do you declare one> 7. /ow do you declare an overloaded stream insertion operator> 10. 0hat is trichotomy and why is it important to C++ pro&rammers> 11. 0hat is transitivity and why is it important to C++ pro&rammers> 12. 'n Cython- it is le&al to use ne&ative array indices to mean 4the element that many positions from the end of the array!6 8or e)ample- m%Arra%[-8] would #e the last element of an arraym%Arra%[-E] the penultimate element- etc! Usin& operator overloadin&- it's possi#le to implement this functionality for a custom array class! 2o you think it's a &ood idea to do so> 0hy or why not> Think a#out the principle of least astonishment when answerin&!

Chapter /%& :perator :verloading

1 @@? 1

13. 0hy is it #etter to implement ! in terms of != instead of != in terms of !> 5+int& Thin* about the number o$ ob!ects created using 12 and using 1 6 14. Consider the followin& definition of a 6$an struct=
stru*t 6$an { int start, sto$; #;

The 6$an struct allows us to define the ran&e of elements from N start- sto$L as a sin&le varia#le! 3iven this definition of 6$an and assumin& start and sto$ are #oth non1ne&ative- provide another #racket operator for our Je*tor class that selects a ran&e of elements! 1 . Consider the followin& interface for a class that iterates over a container of Elem;%$es=
*lass iterator { $ubli*4 bool o$erator== (*onst iterator? other); bool o$erator1= (*onst iterator? other); iterator o$erator!! (); Elem;%$e3 o$erator3 () *onst; Elem;%$e3 o$erator-) () *onst;

#;

There are several mistakes in the definition of this iterator! 0hat are they> /ow would you fi) them> 1!. The implementation of the grid class's o$erator== and o$erator1= functions implemented those operators in terms of the less1than operator! This is somewhat inefficient- since it's more direct to simply check if the two grids are e5ual or une5ual rather than to use the comparison operators! Fewrite the grid's o$erator== function to directly check whether the grids are identical! Then rewrite o$erator1= in terms of o$erator==!

C.a+ter 118 4esource (anagement


_________________________________________________________________________________________________________

This chapter is a#out two thin&s ( puttin& away your toys when you're done with them- and #rin&in& enou&h of your toys for everyone to share! These are lessons you KhopefullyRL learned in kinder&arten which happen to pop up *ust a#out everywhere in life! 0e're supposed to clean up our own messes so that they don't accumulate and start to interfere with others- and try to avoid ho&&in& thin&s so that others don't hurt us #y tryin& to take those nice thin&s away from us! The focus of this chapter is how to play nice with others when it comes to resources! 'n particular- we will e)plore two of C++'s most misunderstood lan&ua&e features- the copy constructor and the assignment operator! 7y the time you're done readin& this chapter- you should have a much #etter understandin& of how to mana&e resources in ways that will keep your pro&rams runnin& and your fellow pro&rammers happy! The material in this chapter is somewhat dense- #ut fear notR 0e'll make sure to &o over all of the important points neatly and methodically! Consider the ST ve*tor! 'nternally- ve*tor is #acked #y a dynamically1allocated array whose size &rows when additional space is needed for more elements! 8or e)ample- a ten1element ve*tor mi&ht store those elements in an array of size si)teen- increasin& the array size if we call $ushLba*B seven more times! 3iven this description- consider the followin& code=
ve*tor int) one(BKum(nts); for(siUeLt B = 0; B one.siUe(); !!B) one.$ushLba*B(int(B)); ve*tor int) t'o = one;

'n the first three lines- we fill one with the first BKum(nts inte&ers- and in the last line we create a new ve*tor called t'o that's a copy of one! /ow does C++ know how to correctly copy the data from one into t'o> 't can't simply copy the pointer to the dynamically1allocated array from one into t'o- since that would cause one and t'o to share the same data and chan&es to one ve*tor would show up in the other! Somehow C++ is aware that to copy a ve*tor it needs to dynamically allocate a new array of elementsthen copy the elements from the source to the destination! This is not done #y ma&ic- #ut #y two special functions called the copy constructor and the assignment operator- which control how to copy instances of a particular class! 7efore discussin& the particulars of the copy constructor and assi&nment operator- we first need to dissect e)actly how an o#*ect can #e copied! 'n order to copy an o#*ect- we first have to answer an important 5uestion ( where do we put the copy> 2o we store it in a new o#*ect- or do we reuse an e)istin& o#*ect> These two options are fundamentally different from one another and C++ makes an e)plicit distinction #etween them! The first option ( puttin& the copy into a new location ( creates the copy #y initiali8ing the new o#*ect to the value of the o#*ect to copy! The second ( storin& the copy in an e)istin& varia#le ( creates the copy #y assigning the e)istin& o#*ect the value of the o#*ect to copy! 0hat do these two copy mechanisms look like in C++> That is- when is an o#*ect initialized to a value- and when is it assi&ned a new value> 'n C++- initialization can occur in three different places=

1 @@E 1

Chapter //& Gesource -anagement

1. A variable is created as a copy o$ an e4isting value 8or e)ample- suppose we write the followin& code=
:%5lass one; :%5lass t'o = one;

/ere- since t'o is told to hold the value of one- C++ will initiali8e t'o as a copy of one! ,lthou&h it looks like we're assi&nin& a value to t'o usin& the = operator- since it is a newly1created o#*ect- the = indicates initialization- not assi&nment! 'n fact- the a#ove code is e5uivalent to the more e)plicit initialization code #elow=
:%5lass one; :%5lass t'o(one); "" (denti*al to above.

This synta) makes more clear that t'o is #ein& created as a copy of one- indicatin& initialization rather than assi&nment! 2. An ob!ect is passed by value to a $unction Consider the followin& function=
void :%&un*tion(:%5lass arg) { "3 ... 3" #

'f we write
:%5lass m*; :%&un*tion(m*);

Then the function :%&un*tion somehow has to set up the value of arg inside the function to have the same value as m* outside the function! Since arg is a new varia#le- C++ will initiali8e it as a copy of m*! 3. An ob!ect is returned $rom a $unction by value Suppose we have the followin& function=
:%5lass :%&un*tion() { :%5lass m*; return m*; #

0hen the statement return m* e)ecutes- C++ needs to return the m* o#*ect from the function! /owever- m* is a local varia#le inside the :%&un*tion function- and to communicate its value to the :%&un*tion caller C++ needs to create a copy of m* #efore it is lost! This is done #y creatin& a temporary :%5lass o#*ect for the return value- then initiali8ing it to #e a copy of m*! "otice that in all three cases- initialization took place #ecause some new o#*ect was created as a copy of an e)istin& o#*ect! 'n the first case this was a new local varia#le- in the second a function parameter- and in the third a temporary o#*ect! ,ssi&nment in C++ is much simpler than initialization and only occurs if an e)istin& o#*ect is e)plicitly assi&ned a new value! 8or e)ample- the followin& code will assign t'o the value of one- rather than initiali8ing t'o to one=

Chapter //& Gesource -anagement


:%5lass one, t'o; t'o = one;

1 @@< 1

't can #e tricky to differentiate #etween initialization and assi&nment #ecause in some cases the synta) is almost identical! 8or e)ample- if we rewrite the a#ove code as
:%5lass one; :%5lass t'o = one; t'o is now initialized to one #ecause it is declared as a new varia#le!

,lways remem#er that the

assi&nment only occurs when &ivin& an e)istin& o#*ect a new value!

0hy is it important to differentiate #etween assi&nment and initialization> ,fter all- they're 5uite similarQ in #oth cases we end up with a new copy of an e)istin& o#*ect! /owever- assi&nment and initialization are fundamentally different operations! 0hen initiali8ing a new o#*ect as a copy of an e)istin& o#*ect- we simply need to copy the e)istin& o#*ect into the new o#*ect! 0hen assigning an e)istin& o#*ect a new valuethe e)istin& o#*ect's value ceases to #e and we must make sure to clean up any resources the o#*ect may have allocated #efore settin& it to the new value! 'n other words- initialization is a strai&ht copy- while assi&nment is cleanup followed #y a copy! This distinction will #ecome manifest in the code we will write for the copy functions later in this chapter! Co+/ 2unctions8 Co+/ Constructors and Assignment $+erators 7ecause initialization and assi&nment are separate tasks- C++ handles them throu&h two different functions called the copy constructor and the assignment operator! The copy constructor is a special constructor responsi#le for initializin& new class instances as copies of e)istin& instances of the class! The assi&nment operator is a special function called an overloaded operator Ksee the chapter on operator overloadin& for more detailsL responsi#le for assi&nin& the receiver o#*ect the value of some other instance of the o#*ect! Thus the code
:%5lass one; :%5lass t'o = one;

will initialize t'o to one usin& the copy constructor- while the code
:%5lass one, t'o; t'o = one;

will assi&n one to t'o usin& the assi&nment operator! Syntactically- the copy constructor is written as a one1ar&ument constructor whose parameter is another instance of the class accepted #y reference1to1*onst! 8or e)ample- &iven the followin& class=
*lass :%5lass { $ubli*4 :%5lass(); c:%5lass(); "3 ... 3" #;

The copy constructor would #e declared as follows=

1 @A0 1
*lass :%5lass { $ubli*4 :%5lass(); c:%5lass();

Chapter //& Gesource -anagement

:%5lass(*onst :%5lass? other); "" 5o$% *onstru*tor "3 ... 3" #;

The synta) for the assi&nment operator is su#stantially more comple) than that of the copy constructor #ecause it is an overloaded operatorQ in particular- o$erator =! 8or reasons that will #ecome clearer later in the chapter- the assi&nment operator should accept as a parameter another instance of the class #y reference1to1*onst and should return a non1*onst reference to an o#*ect of the class type! 8or a concrete e)ample- here's the assi&nment operator for :%5lass=
*lass :%5lass { $ubli*4 :%5lass(); c:%5lass(); :%5lass(*onst :%5lass? other); "" 5o$% *onstru*tor :%5lass? o$erator = (*onst :%5lass? other); "" Assignment o$erator "3 ... 3" #;

0e'll defer discussin& e)actly why this synta) is correct until later- so for now you should take it on faith! 1.at C99 Does 2or Mou Unless you specify otherwise- C++ will automatically provide any class you write with a #asic copy constructor and assi&nment operator that invoke the copy constructors and assi&nment operators of all the class's data mem#ers! 'n many cases- this is e)actly what you want! 8or e)ample- consider the followin& class=
*lass 9efault5lass { $ubli*4 "3 ... 3" $rivate4 int m%(nt; string m%6tring; #;

Suppose you have the followin& code=


9efault5lass one; 9efault5lass t'o = one;

The line 9efault5lass t'o = one will invoke the copy constructor for 9efault5lass! Since we haven't e)plicitly provided our own copy constructor- C++ will initialize t'o.m%(nt to the value of one.m%(nt and t'o.m%6tring to one.m%6tring! Since int is a primitive and string has a well1defined copy constructor- this code is totally fine!

Chapter //& Gesource -anagement

1 @A1 1

/owever- in many cases this is not the #ehavior you want! et's consider the e)ample of a class Je*tor that acts as a wrapper for a dynamic array! Suppose we define Je*tor as shown here=
*lass Je*tor { $ubli*4 Je*tor(); cJe*tor(); "3 Kote4 Ko *o$% *onstru*tor or assignment o$erator 3" "3 ... 3" $rivate4 int3 elems; "3 ... 3" #;

/ere- if we rely on C++'s default copy constructor or assi&nment operator- we'll run into trou#le! 8or e)ample- consider the followin& code=
Je*tor one; Je*tor t'o = one;

7ecause we haven't provided a copy constructor- C++ will initialize t'o.elems to one.elems! Since elems is an int3- instead of &ettin& a deep copy of the elements- we'll end up with two pointers to the same array! Thus chan&es to one will show up in t'o and vice1versa! This is dan&erous- especially when the destructors for #oth one and t'o try to deallocate the memory for elems! 'n situations like theseyou'll need to override C++'s default #ehavior #y providin& your own copy constructors and assi&nment operators! There are a few circumstances where C++ does not automatically provide default copy constructors and assi&nment operators! 'f your class contains a reference or *onst varia#le as a data mem#er- your class will not automatically &et an assi&nment operator! Similarly- if your class has a data mem#er that doesn't have a copy constructor or assi&nment operator Kfor e)ample- an ifstreamL- your class won't #e copya#le! There is one other case involvin& inheritance where C++ won't automatically create the copy functions for you- and in the chapter on inheritance we'll see how to e)ploit this to disa#le copyin&! T.e 4ule of T.ree There's a well1esta#lished C++ principle called the 4rule of three6 that identifies most spots where you'll need to write your own copy constructor and assi&nment operator! 'f this were a math te)t#ook- you'd pro#a#ly see the rule of three written out like this= T.eorem (The Rule of Three)8 'f a class has any of the followin& three mem#er functions= 2estructor Copy Constructor ,ssi&nment Gperator Then that class should have all three of those functions! Corollar/8 'f a class has a destructor- it should also have a copy constructor and assi&nment operator! The rule of three holds #ecause in almost all situations where you have any of the a#ove functions- C++'s default #ehavior won't correctly mana&e your o#*ects! 'n the a#ove e)ample with Je*tor- this is the case #ecause copyin& the elems3 pointer doesn't actually duplicate the elements array! Similarly- if you have a

1 @A; 1

Chapter //& Gesource -anagement

class holdin& an open file handle- makin& a shallow copy of the o#*ect mi&ht cause crashes further down the line as the destructor of one class closed the file handle- corruptin& the internal state of all 4copies6 of that o#*ect! 7oth C++ li#raries and fellow C++ coders will e)pect that- #arrin& special circumstances- all o#*ects will correctly implement the three a#ove functions- either #y fallin& #ack on C++'s default versions or #y e)plicitly providin& correct implementations! Conse5uently- you must keep the rule of three in mind when desi&nin& classes or you will end up with insidious or seemin&ly untracea#le #u&s as your classes start to destructively interfere with each other! 1riting Co+/ Constructors 8or the rest of this chapter- we'll discuss copy constructors and assi&nment operators throu&h a case study of a Je*tor class- a &eneralization of the a#ove Je*tor which #ehaves similarly to the ST ve*tor! The class definition for Je*tor looks like this=
tem$late t%$ename ;) *lass Je*tor { $ubli*4 Je*tor(); Je*tor(*onst Je*tor? other); "" 5o$% *onstru*tor Je*tor? o$erator =(*onst Je*tor? other); "" Assignment o$erator cJe*tor(); t%$edef ;3 iterator; t%$edef *onst ;3 *onstLiterator; iterator begin(); iterator end(); *onstLiterator begin() *onst; *onstLiterator end() *onst; "3 ... other member fun*tions ... 3" $rivate4 ;3 arra%; siUeLt allo*ated7ength; siUeLt logi*al7ength; stati* *onst siUe B6tart6iUe = 8N; #;

'nternally- Je*tor is implemented as a dynamically1allocated array of elements! Two data mem#ersallo*ated7ength and logi*al7ength- track the allocated size of the array and the num#er of elements stored in it- respectively! Je*tor also has a class constant B6tart6iUe that represents the default size of the allocated array! The Je*tor constructor is defined as
tem$late t%$ename ;) Je*tor ;)44Je*tor() { allo*ated7ength = B6tart6iUe; logi*al7ength = 0; arra% = ne' ;[allo*ated7ength]; #

Similarly- the Je*tor destructor is

Chapter //& Gesource -anagement


tem$late t%$ename ;) Je*tor ;)44cJe*tor() { delete [] arra%; #

1 @A@ 1

"ow- let's write the copy constructor! 0e know that we need to match the prototype &iven in the class definition- so we'll write that part first=
tem$late t%$ename ;) Je*tor ;)44Je*tor(*onst Je*tor? other) { "3 ... 3" #

'nside the copy constructor- we need to initialize the o#*ect so that we're holdin& a deep copy of the other Je*tor! This necessitates makin& a full deep1copy of the other Je*tor's array- as well as copyin& over information a#out the size and capacity of the other Je*tor! This second step is relatively strai&htforward- and can #e done as follows=
tem$late t%$ename ;) Je*tor ;)44Je*tor(*onst 9ebugJe*tor? other) { logi*al7ength = other.logi*al7ength; allo*ated7ength = other.allo*ated7ength; "3 ... 3" #

"ote that this implementation of the copy constructor sets logi*al7ength to other.logi*al7ength and allo*ated7ength to other.allo*ated7ength- even thou&h other.logi*al7ength and other.allo*ated7ength e)plicitly reference private data mem#ers of the other o#*ect! This is le&al #ecause other is an o#*ect of type Je*tor and the copy constructor is a mem#er function of Je*tor! , class can access #oth its private fields and private fields of other o#*ects of the same type! This is called sibling access and is true of any mem#er function- not *ust the copy constructor! 'f the copy constructor were not a mem#er of Je*tor or if other were not a Je*tor- this code would not #e le&al! "ow- we'll make a deep copy of the other Je*tor's elements #y allocatin& a new array that's the same size as other's and then copyin& the elements over! The code looks somethin& like this=
tem$late t%$ename ;) Je*tor ;)44Je*tor(*onst Je*tor? other) { logi*al7ength = other.logi*al7ength; allo*ated7ength = other.allo*ated7ength; arra% = ne' ;[allo*ated7ength]; for(siUeLt i = 0; i logi*al7ength; !!i) arra%[i] = other.arra%[i];

'nterestin&ly- since Je*tor is a template- it's unclear what the line arra%[i] = other.arra%[i] will actually do! 'f we're storin& primitive types- then the line will simply copy the values over- #ut if we're storin& o#*ects- the line invokes the class's assi&nment operator! "otice that in #oth cases the o#*ect will #e correctly copied over! This is one of drivin& forces #ehind definin& copy constructors and assi&nment operators- since template code can assume that e)pressions like ob>e*t8 = ob>e*tE will #e meanin&ful! ,n alternative means for copyin& data over from the other o#*ect uses the ST *o$% al&orithm! Fecall that *o$% takes three parameters ( two delineatin& an input ran&e of iterators and one denotin& the #e&innin& of an output ran&e ( then copies the specified iterator ran&e to the destination! ,lthou&h desi&ned to work on iterators- it is possi#le to apply ST al&orithms directly to ran&es defined #y raw C++ pointers! Thus we could rewrite the copy constructor as follows=

1 @AA 1

Chapter //& Gesource -anagement

tem$late t%$ename ;) Je*tor ;)44Je*tor(*onst Je*tor? other) { logi*al7ength = other.logi*al7ength; allo*ated7ength = other.allo*ated7ength; arra% = ne' ;[allo*ated7ength]; *o$%(other.begin(), other.end(), arra%); #

/ere- the ran&e spanned #y other.begin() and other.end() is the entire contents of the other Je*torand arra% is the #e&innin& of the newly1allocated data we've reserved for this Je*tor! ' personally find this synta) prefera#le to the e)plicit for loop- since it increases reada#ility! ,t this point we have a complete and correct implementation of the copy constructor! The code for this constructor is not particularly dense- and it's remarka#ly strai&htforward! 'n some cases- however- it can #e a #it trickier to write a copy constructor! 0e'll see some of these cases later in the chapter! 1riting Assignment $+erators 0e've now successfully written a copy constructor for our Je*tor class! Unfortunately- writin& an assi&nment operator is si&nificantly more involved than writin& a copy constructor! C++ is desi&ned to &ive you ma)imum fle)i#ility when desi&nin& an assi&nment operator- and thus won't alert you if you've written a syntactically le&al assi&nment operator that is completely incorrect! 8or e)ample- consider this le&al #ut incorrect assi&nment operator for an o#*ect of type :%5lass=
void :%5lass44o$erator =(*onst :%5lass? other) { *out /(Am sorr%, 9ave. (Am afraid ( *anAt *o$% that ob>e*t./ # endl;

/ere- if we write code like this=


:%5lass one, t'o; t'o = one;

'nstead of makin& t'o a deep copy of one- instead we'll &et a messa&e printed to the screen and t'o will remain unchan&ed! This is one of the dan&ers of a poorly1written assi&nment operator ( code that looks like it does one thin& can instead do somethin& totally different! This section discusses how to correctly implement an assi&nment operator #y startin& with invalid code and pro&ressin& towards a correct- final version! et's start off with a simple #ut incorrect version of the assi&nment operator for Je*tor! 'ntuitively- since #oth the copy constructor and the assi&nment operator make a copy of another o#*ect- we mi&ht consider implementin& the assi&nment operator #y naively copyin& the code from the copy constructor into the assi&nment operator! This results in the followin& KincorrectRL version of the assi&nment operator=
"3 :an% ma>or mistaBes here. =o not use this code as a reference! 3" tem$late t%$ename ;) void Je*tor ;)44o$erator= (*onst Je*tor? other) { logi*al7ength = other.logi*al7ength; allo*ated7ength = other.allo*ated7ength; arra% = ne' ;[allo*ated7ength]; *o$%(other.begin(), other.end(), arra%);

This code is #ased off the copy constructor- which we used to initialize the o#*ect as a copy of an e)istin& o#*ect! Unfortunately- this code contains a su#stantial num#er of mistakes that we'll need to correct

Chapter //& Gesource -anagement

1 @A? 1

#efore we end up with the final version of the function! Cerhaps the most serious error here is the line arra% = ne' ;[allo*ated7ength]! 0hen the assi&nment operator is invoked- this Je*tor already holds its own array of elements! This line therefore orphans the old array and leaks memory! To fi) this#efore we make this o#*ect a copy of the one specified #y the parameter- we'll take care of the necessary deallocations! This is shown here= 'f you'll notice- we've already written the necessary cleanup code in the 9ebugJe*tor destructor! Father than rewritin& this code- we'll decompose out the &eneric cleanup code into a *lear function- as shown here=
"3 :an% ma>or mistaBes here. 2o not use this code as a referenceR 3" tem$late t%$ename ;) void Je*tor ;)44o$erator= (*onst Je*tor? other) { delete [] arra%; logi*al7ength = other.logi*al7ength; allo*ated7ength = other.allo*ated7ength; arra% = ne' ;[allo*ated7ength]; *o$%(other.begin(), other.end(), arra%); #

,t this point- we can make a particularly useful o#servation! 'f you'll notice- the cleanup code to free the e)istin& array is identical to the code for the destructor- which has the same task! This is no coincidence! 'n &eneral- when writin& an assi&nment operator- the assi&nment operator will need to free all of the resources ac5uired #y the o#*ect- much in the same way that the destructor must! To avoid unnecessary code duplication- we can factor out the code to free the Je*tor's resources into a helper function called *lear()- which is shown here=
tem$late t%$ename ;) void Je*tor ;)44*lear() { delete [] arra%; #

0e can then rewrite the destructor as


tem$late t%$ename ;) Je*tor ;)44cJe*tor() { *lear(); #

,nd we can insert this call to *lear into our assi&nment operator as follows=
"3 ;his *ode still has errors. =o not use it as a reference! 3" tem$late t%$ename ;) void Je*tor ;)44o$erator= (*onst Je*tor? other) { *lear(); logi*al7ength = other.logi*al7ength; allo*ated7ength = other.allo*ated7ength; arra% = ne' ;[allo*ated7ength]; *o$%(other.begin(), other.end(), arra%);

,lon& the same lines- you mi&ht have noticed that all of the code after the call to *lear is e)actly the same code we wrote inside the #ody of the copy constructor! This isn't a coincidence ( in fact- in most cases you'll have a &ood deal of overlap #etween the assi&nment operator and copy constructor! Since we can't

1 @A6 1

Chapter //& Gesource -anagement

invoke our own copy constructor directly Kor any constructor- for that matterL- instead we'll decompose the copyin& code into a mem#er function called *o$%=ther as follows=
tem$late t%$ename ;) void Je*tor ;)44*o$%=ther(*onst Je*tor? other) { logi*al7ength = other.logi*al7ength; allo*ated7ength = other.allo*ated7ength; arra% = ne' ;[allo*ated7ength]; *o$%(other.begin(), other.end(), arra%);

"ow we can rewrite the copy constructor as


tem$late t%$ename ;) Je*tor ;)44Je*tor(*onst Je*tor? other) { *o$%=ther(other); #

,nd the assi&nment operator as


"3 Kot [uite $erfe*t %et. =o not use this code as a reference! 3" tem$late t%$ename ;) void Je*tor ;)44o$erator= (*onst Je*tor? other) { *lear(); *o$%=ther(other); #

This simplifies the copy constructor and assi&nment operator and hi&hli&hts the &eneral pattern of what the two functions should do! 0ith a copy constructor- you'll simply copy the contents of the other o#*ect! 0ith an assi&nment operator- you'll clear out the receiver o#*ect- then copy over the data from another o#*ect! /owever- we're still not done yet! There are two more issues we need to fi) with our current implementation of the assi&nment operator! The first one has to do with sel$"assignment ! Consider- for e)ample- the followin& code=
:%5lass one; one = one;

0hile this code mi&ht seem a #it silly- cases like this come up fre5uently when accessin& elements indirectly throu&h pointers or references! Unfortunately- with our current 9ebugJe*tor assi&nment operator- this code will lead to unusual runtime #ehavior- possi#ly includin& a crash! To see why- let's trace out the state of our o#*ect when its assi&nment operator is invoked on itself! ,t the start of the assi&nment operator- we call *lear to clean out the o#*ect for the copy! 2urin& this call to *lear- we deallocate the memory associated with the o#*ect! 0e then invoke the *o$%=ther function to set the current o#*ect to #e a copy of the receiver o#*ect! Unfortunately- thin&s don't &o 5uite as e)pected! 7ecause we're assi&nin& the o#*ect to itself- the parameter to the assi&nment operator is the receiver o#*ect itself! This means that when we called *lear tryin& to clean up the resources associated with the receiver o#*ect- we also cleaned up all the resources associated with the parameter to the assi&nment operator! 'n other words- *lear destroyed #oth the data we wanted to clean up and the data we were meanin& to copy! The call to *o$%=ther will therefore copy &ar#a&e data into the receiver o#*ectsince the resources it means to copy have already #een cleaned up! This is e)tremely #ad- and will almost certainly cause a pro&ram crash!

Chapter //& Gesource -anagement

1 @AD 1

0hen writin& assi&nment operators- you must ensure that your code correctly handles self1assi&nment! 0hile there are many ways we can do this- perhaps the simplest is to simply check to make sure that the o#*ect to copy isn't the same o#*ect pointed at #y the this pointer! The code for this lo&ic looks like this=
"3 Kot [uite $erfe*t %et. =o not use this code as a reference! 3" tem$late t%$ename ;) void Je*tor ;)44o$erator= (*onst Je*tor? other) { if(this 1= ?other) { *lear(); *o$%=ther(other); # #

"ote that we check if(this 1= ?other)! That is- we compare the addresses of the current o#*ect and the parameter! This will determine whether or not the o#*ect we're copyin& is e)actly the same o#*ect as the one we're workin& with! 'n the practice pro#lems for this chapter- you'll e)plore what would happen if you were to write if(3this 1= other)! Gne detail worth mentionin& is that the self1assi&nment check is not necessary in the copy constructor- since an o#*ect can't #e a parameter to its own constructor! There's one final #u& we need to sort out- and it has to do with how we're le&ally allowed to use the = operator! Consider- for e)ample- the followin& code=
:%5lass one, t'o, three; three = t'o = one;

This code is e5uivalent to three = (t'o = one)! Since our current assi&nment operator does not return a value- (t'o = one) does not have a value- so the a#ove statement is meanin&less and the code will not compile! 0e thus need to chan&e our assi&nment operator so that performin& an assi&nment like t'o = one yields a value that can then #e assi&ned to other values! The final version of our assi&nment operator is thus
"3 ;he correct version of the assignment o$erator. 3" tem$late t%$ename ;) Je*tor ;)? Je*tor ;)44o$erator= (*onst Je*tor? other) { if(this 1= ?other) { *lear(); *o$%=ther(other); # return 3this; #

$ne eneral !attern ,lthou&h each class is different- in many cases the default constructor- copy constructor- assi&nment operator- and destructor will share a &eneral pattern! /ere is one possi#le skeleton you can fill in to &et your copy constructor and assi&nment operator workin&!
:%5lass44:%5lass() 4 "3 &ill in initialiUer list. 3" { "3 9efault initialiUation here. 3" # :%5lass44:%5lass(*onst :%5lass? other) { *o$%=ther(other); #

1 @AE 1

Chapter //& Gesource -anagement

:%5lass? :%5lass44o$erator =(*onst :%5lass? other) { if(this 1= ?other) { *lear(); "" Kote4 2hen 'e *over inheritan*e, thereAs one more ste$ here. *o$%=ther(other); # return 3this; # :%5lass44c:%5lass() { *lear(); #

6emantic )Jui;alence and copyAther 6trategies Consider the followin& code snippet=
Je*tor int) one; Je*tor int) t'o = one;

/ere- we know that t'o is a copy of one- so the two o#*ects should #ehave identically to one another! 8or e)ample- if we access an element of one- we should &et the same value as if we had accessed the correspondin& element of t'o and vice1versa! /owever- while one and t'o are indistin&uisha#le from each other in terms of functionality- their memory representations are not identical #ecause one and t'o point to two different dynamically1allocated arrays! This raises the distinction #etween semantic e@uivalence and bitwise e@uivalence! Two o#*ects are said to #e bitwise e@uivalent if they have identical representations in memory! 8or e)ample- any two ints with the value 1@D are #itwise e5uivalent- and if we define a $oint; struct as a pair of ints- any two $oint;s holdin& the same values will #e #itwise e5uivalent! Two o#*ects are semantically e@uivalent if- like one and t'o- any operations performed on the o#*ects will yield identical results! 0hen writin& a copy constructor and assi&nment operator- you attempt to convert an o#*ect into a semantically e5uivalent copy of another o#*ect! Conse5uently- you are free to pick any copyin& strate&y that creates a semantically e5uivalent copy of the source o#*ect! 'n the precedin& section- we outlined one possi#le implementation strate&y for a copy constructor and assi&nment operator that uses a shared function called *o$%=ther! 0hile in the case of the 9ebugJe*tor it was relatively easy to come up with a workin& *o$%=ther implementation- when workin& with more complicated o#*ects- it can #e difficult to devise a workin& *o$%=ther! 8or e)ample- consider the followin& class- which represents a mathematical set implemented as a linked list=

Chapter //& Gesource -anagement


tem$late t%$ename ;) *lass 7ist6et { $ubli*4 7ist6et(); 7ist6et(*onst 7ist6et? other); 7ist6et? o$erator =(*onst 7ist6et? other); c7ist6et(); void insert(*onst ;? toAdd); bool *ontains(*onst ;? to&ind) *onst; $rivate4 stru*t *ell; { ; data; *ell;3 ne+t; #; *ell;3 list; void *o$%=ther(*onst 7ist6et? other); void *lear();

1 @A< 1

#;

This 7ist6et class e)ports two functions- insert and *ontains- that insert an element into the list and determine whether the list contains an element- respectively! This class represents a mathematical set- an unordered collection of elements- so the underlyin& linked list need not #e in any particular order! 8or e)ample- the lists {0, 8, E, C, G# and {G, C, E, 8, 0# are semantically e5uivalent #ecause checkin& whether a num#er is an element of the first list yields the same result as checkin& whether the num#er is in the second! 'n fact- any two lists containin& the same elements are semantically e5uivalent to one another! This means that there are multiple ways in which we could implement *o$%=ther! Consider these two=
"3 Kersion 1" 9u$li*ate the list as it e+ists in the original 7ist6et. 3" tem$late t%$ename ;) void 7ist6et ;)44*o$%=ther(*onst 7ist6et? other) { "3 Wee$ tra*B of 'hat the *urrent linBed list *ell is. 3" *ell;33 *urrent = ?list; "3 (terate over the sour*e list. 3" for(*ell;3 sour*e = other.list; sour*e 1= K@77; sour*e = sour*e-)ne+t) { "3 9u$li*ate the *ell. 3" 3*urrent = ne' *ell;; (3*urrent)-)data = sour*e-)data; (3*urrent)-)ne+t = K@77; "3 Advan*e to ne+t element. 3" *urrent = ?((3*urrent)-)ne+t); # #

"3 Kersion (" 9u$li*ate list in reverse order of original 7ist6et 3" tem$late t%$ename ;) void 7ist6et ;)44*o$%=ther(*onst 7ist6et? other) { for(*ell;3 sour*e = other.list; sour*e 1= K@77; sour*e = sour*e-)ne+t) { *ell;3 ne'Kode = ne' *ell;; ne'Kode-)data = sour*e-)data; ne'Kode-)ne+t = list; list = ne'Kode; # #

1 @?0 1

Chapter //& Gesource -anagement

,s you can see- the second version of this function is much- much cleaner than the first! There are no address1of operators floatin& around- so everythin& is e)pressed in terms of simpler pointer operations! 7ut while the second version is cleaner than the first- it duplicates the list in reverse order! This may initially seem pro#lematic #ut is actually perfectly safe! ,s the ori&inal o#*ect and the duplicate o#*ect contain the same elements in some order- they will #e semantically e5uivalent- and from the class interface we would #e una#le to distin&uish the ori&inal o#*ect and its copy! There is one implementation of *o$%=ther that is considera#ly more ele&ant than either of the two versions listed a#ove=
"3 Kersion 3" 9u$li*ate list using the insert fun*tion 3" tem$late t%$ename ;) void 7ist6et ;)44*o$%=ther(*onst 7ist6et? other) { for(*ell;3 sour*e = other.list; sour*e 1= K@77; sour*e = sour*e-)ne+t) insert(sour*e-)data); #

"otice that this implementation uses the 7ist6et's pu#lic interface to insert the elements from the source 7ist6et into the receiver o#*ect! This version of *o$%=ther is un5uestiona#ly the cleanest! 'f you'll notice- it doesn't matter e)actly how insert adds elements into the list Kindeed- insert could insert the elements at random positionsL- #ut we're &uaranteed that at the end of the *o$%=ther call- the receiver o#*ect will #e semantically e5uivalent to the parameter! Con;ersion Assignment $+erators 0hen workin& with copy constructors- we needed to define an additional function- the assi&nment operator- to handle all the cases in which an o#*ect can #e copied or assi&ned! /owever- in the chapter on conversion constructors- we provided a conversion constructor without a matchin& 4conversion assi&nment operator!6 't turns out that this is not a pro#lem #ecause of how the assi&nment operator is invoked! Suppose that we have a 56tring class that has a defined copy constructor- assi&nment operatorand conversion constructor that converts raw C++ *har 3 pointers into 56tring o#*ects! "ow- suppose we write the followin& code=
56tring m%56tring; m%56tring = /;his is a 5 string1/;

/ere- in the second line- we assi&n an e)istin& 56tring a new value e5ual to a raw C strin&! 2espite the fact that we haven't defined a special assi&nment operator to handle this case- the a#ove is perfectly le&al code! 0hen we write the line
m%56tring = /;his is a 5 string1/;

C++ converts it into the e5uivalent code


m%56tring.o$erator= (/;his is a 5 string1/);

This synta) may look entirely forei&n- #ut is simply a direct call to the assi&nment operator! Fecall that the assi&nment operator is a function named o$erator =- so this code passes the C strin& /;his is a 5 string1/ as a parameter to o$erator =! 7ecause o$erator = accepts a 56tring o#*ect rather than a raw C strin&- C++ will invoke the 56tring conversion constructor to initialize the parameter to o$erator =! Thus this code is e5uivalent to
m%56tring.o$erator =(56tring(/;his is a 5 string1/))E

Chapter //& Gesource -anagement

1 @?1 1

'n other words- the conversion constructor converts the raw C strin& into a 56tring o#*ect- then the assi&nment operator sets the receiver o#*ect e5ual to this temporary 56tring! 'n &eneral- you need not provide a 4conversion assi&nment operator6 to pair with a conversion constructor! ,s lon& as you've provided well1defined copy #ehavior- C++ will link the conversion constructor and assi&nment operator to&ether to perform the assi&nment! Disabling Co+/ing 'n CS1067HI we provide you the 9(6A77=2L5=<S(KG macro- which causes a compile error if you try to assi&n or copy o#*ects of the specified type! 9(6A77=2L5=<S(KG- however- is not a standard C++ feature! 0ithout usin& the CS1067HI li#rary- how can we replicate the functionality> 0e can't prevent o#*ect copyin& #y simply not definin& a copy constructor and assi&nment operator! ,ll this will do is have C++ provide its own default version of these two functions- which is not at all what we want! To solve this pro#lem- instead we'll provide an assi&nment operator and copy constructor- #ut declare them private so that class clients can't access them! 8or e)ample=
*lass 5annotPe5o$ied { $ubli*4 5annotPe5o$ied(); "3 =ther member fun*tions. 3" $rivate4 5annotPe5o$ied(*onst 5annotPe5o$ied? other); 5annotPe5o$ied? o$erator = (*onst 5annotPe5o$ied? other); #;

"ow- if we write code like this=


5annotPe5o$ied one; 5annotPe5o$ied t'o = one;

0e'll &et a compile1time error on the second line #ecause we're tryin& to invoke the copy constructorwhich has #een declared private! 0e'll &et similar #ehavior when tryin& to use the assi&nment operator! This trick is almost one hundred percent correct- #ut does have one ed&e case= what if we try to invoke the copy constructor or assi&nment operator inside a mem#er function of the class> The copy functions mi&ht #e private- #ut that doesn't mean that they don't e)ist- and if we call them inside a mem#er function mi&ht accidentally create a copy of an otherwise uncopya#le o#*ect! To prevent this from happenin&- we'll use a cute trick! ,lthou&h we'll prototype the copy functions inside the private section of the class- we won't implement them! This means that if we accidentally do mana&e to call either function- we will &et a linker error #ecause the compiler can't find code for either function! This is admittedly a #it hackish- so in C+ +0)- the ne)t revision of C++- there will #e a way to e)plicitly indicate that a class is uncopya#le! 'n the meantime- thou&h- the a#ove approach is perhaps your #est option! 0e'll see another way to do this later when we cover inheritance! )*tended )*am+le8 Imart1ointer 'n C++ parlance- a raw pointer like an int3 or a *har3 is sometimes called a dumb pointer #ecause the pointer has no 4knowled&e6 of the resource it owns! 'f an int3 &oes out of scope- it doesn't inform the o#*ect it's pointin& at and makes no attempt whatsoever to clean it up! The int3 doesn't own its resourceand assi&nin& one int3 to another doesn't make a deep copy of the resource or inform the other int3 that another pointer now references its pointee!

1 @?; 1

Chapter //& Gesource -anagement

7ecause raw pointers are so pro#lematic- many C++ pro&rammers prefer to use smart pointers- o#*ects that mimic raw pointers #ut which perform functions #eyond merely pointin& at a resource! 8or e)amplethe C++ standard li#rary class autoL$tr- which we'll cover in the chapter on e)ception handlin&- acts like a re&ular pointer e)cept that it automatically calls delete on the resource it owns when it &oes out of scope! Gther smart pointers are custom1tuned for specific applications and mi&ht perform functions like lo&&in& access- synchronizin& multithreaded applications- or preventin& accidental null pointer dereferences! Thanks to operator overloadin&- smart pointers can #e #uilt to look very similar to re&ular C++ pointers! 0e can provide an implementation of o$erator 3 to support dereferences like 3m%<trand can define o$erator -) to let clients write code to the effect of m%<tr-)*lear()! Similarly- we can write copy constructors and assi&nment operators for smart pointers that do more than *ust transfer a resource! 4eference Counting Iemory mana/ement in "LL is tric0y. Oo# m#st be care*#l to balance every ne' with e4actly one delete, and m#st ma0e s#re that no other pointers to the reso#rce e4ist a*ter delete)in/ it to ens#re that later on yo# don.t access invalid memory. 2* yo# delete memory too many times yo# r#n into #nde*ined behavior, and i* yo# delete it too *ew yo# have a memory lea0. 2s there a better way to mana/e memory: 2n many cases, yes, and in this e4tended e4ample we.ll see one way to accomplish this #sin/ a techniE#e called reference counting. 2n partic#lar, we.ll desi/n a smart pointer class called 6mart<ointer which acts li0e a re/#lar "LL pointer, e4cept that it #ses re*erence co#ntin/ to prevent reso#rce lea0s. To motivate reference countin&- let's suppose that we have a smart pointer class that stores a pointer to a resource! The destructor for this smart pointer class can then delete the resource automatically- so clients of the smart pointer never need to e)plicitly clean up any resources! This system is fine in restricted circumstances- #ut runs into trou#le as soon as we have several smart pointers pointin& to the same resource! Consider the scenario #elow= Smart Point+r R+&o0r*+ Smart Point+r

7oth of these pointers can access the stored resource- #ut unfortunately neither smart pointer knows of the other's e)istence! /ere we hit a sna&! 'f one smart pointer cleans up the resource while the other still points to it- then the other smart pointer will point to invalid memory! 'f #oth of the pointers try to reclaim the dynamically1allocated memory- we will encounter a runtime error from dou#le1 delete1in& a resource! 8inally- if neither pointer tries to clean up the memory- we'll &et a memory leak! To resolve this pro#lem- we'll use a system called re$erence counting where we will e)plicitly keep track of the num#er of pointers to a dynamically1allocated resource! 0hile there are several ways to make such a system work- perhaps the simplest is to use an intermediary o#*ect! This can #e seen visually=

Chapter //& Gesource -anagement Int+rm+diary

1 @?@ 1

Smart Point+r

R+&o0r*+

"ow- the smart pointer stores a pointer to an intermediary o#*ect rather than a pointer directly to the resource! This intermediary o#*ect has a counter Kcalled a re$erence counterL that tracks the num#er of smart pointers accessin& the resource- as well as a pointer to the mana&ed resource! This intermediary o#*ect lets the smart pointers tell whether or not they are the only pointer to the stored resourceQ if the reference count is anythin& other than one- some other pointer shares the resource! Crovided that we accurately track the reference count- each pointer can tell if it's the last pointer that knows a#out the resource and can determine whether to deallocate it! To see how reference countin& works- let's walk throu&h an e)ample! 3iven the a#ove system- suppose that we want to share the resource with another smart pointer! 0e simply make this new smart pointer point to the same intermediary o#*ect as our ori&inal pointer- then update the reference count! The resultin& scenario looks like this= Smart Point+r Int+rm+diary !

R+&o0r*+

Smart Point+r ,lthou&h in this dia&ram we only have two o#*ects pointin& to the intermediary- the reference1countin& system allows for any num#er of smart pointers to share a sin&le resource! "ow- suppose one of these smart pointers needs to stop pointin& to the resource ( may#e it's #ein& assi&ned to a different resource- or perhaps it's &oin& out of scope! That pointer decrements the reference count of the intermediary varia#le and notices that the reference count is nonzero! This means that at least one smart pointer still references the resource- so the smart pointer simply leaves the resource as it is! Bemory now looks like this=

1 @?A 1 Int+rm+diary

Chapter //& Gesource -anagement

Smart Point+r

R+&o0r*+

8inally- suppose this last smart pointer needs to stop pointin& to this resource! 't decrements the reference count- #ut this time notices that the reference count is zero! This means that no other smart pointers reference this resource- and the smart pointer knows that it needs to deallocate the resource and the intermediary o#*ect- as shown here= Smart Point+r Int+rm+diary 0

R+&o0r*+

The resource has now #een deallocated and no other pointers reference the memory! 0e've safely and effectively cleaned up our resources! Boreover- this process is completely automatic ( the user never needs to e)plicitly deallocate any memory! The followin& summarizes the reference1countin& scheme descri#ed a#ove= 0hen creatin& a smart pointer to mana&e newly1allocated memory- first create an intermediary o#*ect and make the intermediary point to the resource! Then- attach the smart pointer to the intermediary and set the reference count to one! To make a new smart pointer point to the same resource as an e)istin& one- make the new smart pointer point to the old smart pointer's intermediary o#*ect and increment the intermediary's reference count! To remove a smart pointer from a resource Keither #ecause the pointer &oes out of scope or #ecause it's #ein& reassi&nedL- decrement the intermediary o#*ect's reference count! 'f the count reaches zero- deallocate the resource and the intermediary o#*ect!

0hile reference countin& is an e)cellent system for mana&in& memory automatically- it does have its limitations! 'n particular- reference countin& can sometimes fail to clean up memory in 4reference cycles-6 situations where multiple reference1counted pointers hold references to one another! 'f this happensnone of the reference counters can ever drop to zero- since the cyclically1linked elements always refer to one another! 7ut #arrin& this sort of setup- reference countin& is an e)cellent way to automatically mana&e memory! 'n this e)tended e)ample- we'll see how to implement a reference1counted pointer- which we'll

Chapter //& Gesource -anagement

1 @?? 1

call 6mart<ointer- and will e)plore how the correct cocktail of C++ constructs can make the resultin& class slick and efficient! Designing Imart1ointer The a#ove section details the implementation the 6mart<ointer class- #ut we have not talked a#out its inter$ace! 0hat functions should we provide> 0e'll try to make 6mart<ointer resem#le a raw C++ pointer as closely as possi#le- meanin& that it should support o$erator 3 and o$erator -) so that the client can dereference the 6mart<ointer! /ere is one possi#le interface for the 6mart<ointer class=
tem$late t%$ename ;) *lass 6mart<ointer { $ubli*4 e+$li*it 6mart<ointer(;3 memor%); 6mart<ointer(*onst 6mart<ointer? other); 6mart<ointer? o$erator =(*onst 6mart<ointer? other); c6mart<ointer(); ;? o$erator 3 () *onst; ;3 o$erator -) () *onst; #;

/ere is a #reakdown of what each of these functions should do=


e5plicit Imart1ointer3%G memory4E

Constructs a new 6mart<ointer that mana&es the resource specified as the parameter! The reference count is initially set to one! 0e will assume that the provided pointer came from a call to ne'! This function is marked e+$li*it so that we cannot accidentally convert a re&ular C++ pointer to a 6mart<ointer! ,t first this mi&ht seem like a stran&e desi&n decision- #ut it prevents a wide ran&e of su#tle #u&s! 8or e)ample- suppose that this constructor is not e+$li*it and consider the followin& function=
void <rint6tring(*onst 6mart<ointer string)? $tr) { *out 3$tr endl; #

This function accepts a 6mart<ointer #y reference1to1*onst- then prints out the stored strin&! "owwhat happens if we write the followin& code>
string3 $tr = ne' string(/Sa%1/); <rint6tring($tr); delete $tr;

The first line dynamically1allocates a string- passes it to <rint6tring- and finally deallocates it! Unfortunately- this code will almost certainly cause a runtime crash! The pro#lem is that <rint6tring e)pects a 6mart<ointer string) as a parameter- #ut we've provided a string3! C++ notices that the 6mart<ointer string) has a conversion constructor that accepts a string3- and makes a temporary 6mart<ointer string) usin& the pointer we passed as a parameter! This new 6mart<ointer starts trackin& the pointer with a reference count of one! ,fter the function returns- the parameter is cleaned up and its destructor invokes! This decrements the reference count to zero- and then deallocates the pointer stored in the 6mart<ointer! The a#ove code then tries to delete $tr a second time- causin& a runtime crash! To prevent this pro#lem- we'll mark the constructor e+$li*it- which makes the implicit conversion ille&al and prevents this #u&&y code from compilin&!

1 @?6 1

Chapter //& Gesource -anagement

Imart1ointer3const Imart1ointerP other4E

Constructs a new 6mart<ointer that shares the resource contained in another 6mart<ointer- updatin& the reference count appropriately!
Imart1ointerP operatorO3const Imart1ointerP other4E

Causes this 6mart<ointer to stop pointin& to the resource it's currently mana&in& and to share the resource held #y another 6mart<ointer! 'f the smart pointer was the last pointer to its resource- it deletes it!
QImart1ointer34E

2etaches the 6mart<ointer from the resource it's sharin&- freein& the associated memory if necessary!
%P operatorG 34 constE

C,ere*erencesD the pointer and ret#rns a re*erence to the obAect bein/ pointed at. -ote that o$erator3 is *onst5 see the last chapter *or more in*ormation why.
%G operator-: 34 constE

<et#rns the obAect that the arrow operator sho#ld really be applied to i* the arrow is #sed on the 6mart<ointer. +/ain, see the last chapter *or more in*ormation on this. 3iven this pu#lic interface for 6mart<ointer- we can now #e&in implementin& the class! 0e first need to decide on how we should represent the reference1countin& information! Gne simple method is to define a private stru*t inside 6mart<ointer that represents the reference1countin& intermediary! This looks as follows=
tem$late t%$ename ;) *lass 6mart<ointer { $ubli*4 e+$li*it 6mart<ointer(;3 memor%); 6mart<ointer(*onst 6mart<ointer? other); 6mart<ointer? o$erator =(*onst 6mart<ointer? other); c6mart<ointer(); ;? o$erator 3 () *onst; ;3 o$erator -) () *onst; $rivate4 stru*t (ntermediar% { ;3 resour*e; siUeLt ref5ount; #; (ntermediar%3 data; #;

/ere- the resour*e field of the (ntermediar% is the actual pointer to the stored resource and ref5ount is the reference count! "otice that we did not declare the reference count as a direct data mem#er of the 6mart<ointer- #ut rather in the (ntermediar% o#*ect! This is #ecause the reference count of a resource is not owned #y any one 6mart<ointer- #ut rather is shared across all 6mart<ointers that point to a particular resource! This way- any chan&es to the reference count #y one 6mart<ointer will #ecome visi#le in all of the other 6mart<ointers referencin& the resource! .ou mi&ht ask ( could we have made the ref5ount a stati* data mem#er> This would indeed make the reference count visi#le across

Chapter //& Gesource -anagement

1 @?D 1

multiple 6mart<ointers- #ut unfortunately it won't work out correctly! 'n particular- if we use 6mart<ointer to mana&e multiple resources- each one needs to have its own ref5ount or chan&es to the ref5ount for a particular resource will show up in the ref5ount for other resources! 3iven this setup- we can implement the 6mart<ointer constructor #y creatin& a new (ntermediar% that points to the specified resource and has an initial reference count of one=
tem$late t%$ename ;) 6mart<ointer ;)446mart<ointer(;3 res) { data = ne' (ntermediar%; data-)resour*e = res; data-)ref5ount = 8; #

't's very important that we allocate the (ntermediar% o#*ect on the heap rather than as a data mem#er! That way- when the 6mart<ointer is cleaned up Keither #y &oin& out of scope or #y an e)plicit call to deleteL- if it isn't the last pointer to the shared resource- the intermediary o#*ect isn't cleaned up! 0e can similarly implement the destructor #y decrementin& the reference count- then cleanin& up memory if appropriate! "ote that if the reference count hits zero- we need to delete #oth the resource and the intermediary! 8or&ettin& to deallocate either of these leads to memory leaks- the e)act pro#lem we wanted to avoid! The code for this is shown here=
tem$late t%$ename ;) 6mart<ointer ;)44c6mart<ointer() { --data-)ref5ount; if(data-)ref5ount == 0) { delete data-)resour*e; delete data; # #

This is an interestin& destructor in that it isn't &uaranteed to actually clean up any memory! Gf course- this is e)actly the #ehavior we want- since the memory mi&ht #e shared amon& multiple 6mart<ointers! 'mplementin& o$erator 3 and o$erator -) simply re5uires us to access the pointer stored inside the 6mart<ointer! These two functions can #e implemented as follows=P
tem$late t%$ename ;) ;? 6mart<ointer ;)44o$erator 3 () *onst { return 3data-)resour*e; # tem$late t%$ename ;) ;3 6mart<ointer ;)44o$erator -) () *onst { return data-)resour*e; #

"ow- we need to implement the copy #ehavior for this 6mart<ointer! Gne way to do this is to write helper functions clear and *o$%=ther which perform deallo*ation and copyin&! 0e will use a similar
P 't is common to see o$erator
-) implemented as

Iet;%$e3 :%5lass44o$erator -) () *onst { return ?33this; # ?33this is interpreted #y the compiler as ?(3(3this))- which means 4dereference the this pointer to &et the receiver

o#*ect- then dereference the receiver! 8inally- return the address of the referenced o#*ect!6 ,t times this may #e the #est way to implement o$erator -)- #ut ' advise a&ainst it in &eneral #ecause it's fairly cryptic!

1 @?E 1

Chapter //& Gesource -anagement

approach here- e)cept usin& functions named deta*h and atta*h to make e)plicit the operations we're performin&! This leads to the followin& definition of 6mart<ointer=
tem$late t%$ename ;) *lass 6mart<ointer { $ubli*4 e+$li*it 6mart<ointer(;3 memor%); 6mart<ointer(*onst 6mart<ointer? other); 6mart<ointer? o$erator =(*onst 6mart<ointer? other); c6mart<ointer(); ;? o$erator 3 () *onst; ;3 o$erator -) () *onst; $rivate4 stru*t (ntermediar% { ;3 resour*e; siUeLt ref5ount; #; (ntermediar%3 data; void deta*h(); void atta*h((ntermediar%3 other);

#;

"ow- what should these functions do> The first of these- deta*h- should detach the 6mart<ointer from the shared intermediary and clean up the memory if it was the last pointer to the shared resource! 'n case this sounds familiar- it's #ecause this is e)actly the #ehavior of the 6mart<ointer destructor! To avoid code duplication- we'll move the code from the destructor into detach as shown here=
tem$late t%$ename ;) void 6mart<ointer ;)44deta*h() { --data-)ref5ount; if(data-)ref5ount == 0) { delete data-)resour*e; delete data; # #

0e can then implement the destructor as a wrapped call to detach- as seen here=
tem$late t%$ename ;) 6mart<ointer ;)44c6mart<ointer() { deta*h(); #

The attach function- on the other hand- makes this SmartCointer #e&in pointin& to the specified 'ntermediary and increments the reference count! /ere's one possi#le implementation of attach=
tem$late t%$ename ;) void 6mart<ointer ;)44atta*h((ntermediar%3 to) { data = to; !!data-)ref5ount; #

3iven these two functions- we can implement the copy constructor and assi&nment operator for 6mart<ointer as follows=

Chapter //& Gesource -anagement

1 @?< 1

tem$late t%$ename ;) 6mart<ointer ;)446mart<ointer(*onst 6mart<ointer? other){ atta*h(other.data); # tem$late t%$ename ;) 6mart<ointer ;)? 6mart<ointer ;)44o$erator= (*onst 6mart<ointer? other) { if(this 1= ?other) { deta*h(); atta*h(other.data); # return 3this; #

't is crucial that we check for self1assi&nment inside the o$erator= function- since otherwise we mi&ht destroy the data that we're tryin& to keep track ofR ,t this point we have a rather slick 6mart<ointer class! /ere's some code demonstratin& how a client mi&ht use 6mart<ointer=
6mart<ointer string) m%<tr(ne' string); 3m%<tr = /;his is a string1/; *out 3m%<tr endl; 6mart<ointer string) other = m%<tr; *out 3other endl; *out other-)length() endl;

The #eauty of this code is that client code usin& a 6mart<ointer string) looks almost identical to code usin& a re&ular C++ pointer! 'sn't operator overloadin& wonderful> )*tending Imart1ointer The 6mart<ointer defined a#ove is useful #ut lacks some important functionality! 8or e)ample- suppose that we have the followin& function=
void 9o6omething(string3 $tr);

Suppose that we have a 6mart<ointer string) mana&in& a resource and that we want to pass the stored strin& as a parameter to 9o6omething! 2espite the fact that 6mart<ointer string) mimics a string3- it technically is not a string3 and C++ won't allow us to pass the 6mart<ointer into 9o6omething! Somehow we need a way to have the 6mart<ointer hand #ack the resource it mana&es! "otice that the only 6mart<ointer mem#er functions that &ive #ack a pointer or reference to the actual resource are o$erator3 and o$erator-)! Technically speakin&- we could use these functions to pass the stored string into 9o6omething- #ut the synta) would #e messy Kin the case of o$erator3L or ni&htmarish Kfor o$erator -)L! 8or e)ample=

1 @60 1
6mart<ointer string) m%<tr(ne' string);

Chapter //& Gesource -anagement

"3 ;o use o$erator3 to get the stored resour*e, 'e have to first dereferen*e 3 the 6mart<ointer, then use the address-of o$erator to *onvert the returned 3 referen*e into a $ointer. 3" 9o6omething(?3m%<tr); "3 ;o use o$erator-) to get the stored resour*e, 'e have to e+$li*itl% *all the 3 o$erator-) fun*tion. SiBes1 3" 9o6omething(m%<tr.o$erator-) ());

Somethin& is clearly amiss and we cannot reasona#ly e)pect clients to write code like this routinely! 0e'll need to e)tend the 6mart<ointer class to provide a way to return the stored pointer directly! This necessitates the creation of a new mem#er function- which we'll call &et- to do *ust that! 3iven a function like this- we could then invoke 9o6omething as follows=
9o6omething(m%<tr.get());

The updated interface for 6mart<ointer looks like this=


tem$late t%$ename ;) *lass 6mart<ointer { $ubli*4 e+$li*it 6mart<ointer(;3 memor%); 6mart<ointer(*onst 6mart<ointer? other); 6mart<ointer? o$erator =(*onst 6mart<ointer? other); c6mart<ointer(); ;? o$erator 3 () *onst; ;3 o$erator -) () *onst; ;3 get() *onst; $rivate4 stru*t (ntermediar% { ;3 resour*e; siUeLt ref5ount; #; (ntermediar%3 data; void deta*h(); void atta*h((ntermediar%3 other);

#;

The implementation of &et is fairly strai&htforward and is shown here=


tem$late t%$ename ;) ;3 6mart<ointer ;)44get() *onst { return data-)resour*e; #

2urt.er )*tensions There are several more e)tensions to the 6mart<ointer class that we mi&ht want to consider- of which this section e)plores two! The first is rather strai&htforward! ,t times- we mi&ht want to know e)actly how many 6mart<ointers share a resource! This mi&ht ena#le us to perform some optimizations- in

Chapter //& Gesource -anagement

1 @61 1

particular a techni5ue called copy"on"write! 0e will not e)plore this techni5ue here- thou&h you are encoura&ed to do so on your own! Usin& the same lo&ic as a#ove- we'll define another mem#er function called get6hare5ount which returns the num#er of 6mart<ointers pointin& to the mana&ed resource Kincludin& the receiver o#*ectL! This results in the followin& class definition=
tem$late t%$ename ;) *lass 6mart<ointer { $ubli*4 e+$li*it 6mart<ointer(;3 memor%); 6mart<ointer(*onst 6mart<ointer? other); 6mart<ointer? o$erator =(*onst 6mart<ointer? other); c6mart<ointer(); ;? o$erator 3 () *onst; ;3 o$erator -) () *onst; ;3 get() *onst; siUeLt get6hare5ount() *onst; $rivate4 stru*t (ntermediar% { ;3 resour*e; siUeLt ref5ount; #; (ntermediar%3 data; void deta*h(); void atta*h((ntermediar%3 other); #;

,nd the followin& implementation=


tem$late t%$ename ;) siUeLt 6mart<ointer ;)44get6hare5ount() *onst { return data-)ref5ount; #

The last piece of functionality we'll consider is the a#ility to 4reset6 the 6mart<ointer to point to a different resource! 0hen workin& with a 6mart<ointer- at times we may *ust want to drop whatever resource we're holdin& and #e&in mana&in& a new one! ,s you mi&ht have suspected- we'll add yet another mem#er function called reset which resets the 6mart<ointer to point to a new resource! The final interface and code for reset is shown here=

1 @6; 1

Chapter //& Gesource -anagement

tem$late t%$ename ;) *lass 6mart<ointer { $ubli*4 e+$li*it 6mart<ointer(;3 memor%); 6mart<ointer(*onst 6mart<ointer? other); 6mart<ointer? o$erator =(*onst 6mart<ointer? other); c6mart<ointer(); ;? o$erator 3 () *onst; ;3 o$erator -) () *onst; ;3 get() *onst; siUeLt get6hare5ount() *onst; void reset(;3 ne'Ies); $rivate4 stru*t (ntermediar% { ;3 resour*e; siUeLt ref5ount; #; (ntermediar%3 data; void deta*h(); void atta*h((ntermediar%3 other);

#;

tem$late t%$ename ;) void 6mart<ointer ;)44reset(;3 ne'Ies) { "3 2eAre no longer asso*iated 'ith our *urrent resour*e, so dro$ it. 3" deta*h(); "3 Atta*h to a ne' intermediar% ob>e*t. 3" data = ne' (ntermediar%; data-)resour*e = ne'Ies; data-)ref5ount = 8

!ractice !roblems The only way to learn copy constructors and assi&nment operators is to play around with them to &ain e)perience! /ere are some practice pro#lems and thou&ht 5uestions to &et you started= 1. 0hen is the copy constructor invoked> 2. 0hen is the assi&nment operator invoked> 3. 0hat is the si&nature of the copy constructor> 4. 0hat is the si&nature of the assi&nment operator> . 0hat is the rule of three> 0hat are the 4three6 it refers to> !. 0hat is the #ehavior of the default1&enerated copy constructor and assi&nment operator> $. 0hy does the assi&nment operator have to check for self1assi&nment #ut the copy constructor not need to check for 4self1initialization>6 6. 0hat is #itwise e5uivalence> 0hat is semantic e5uivalence> 0hich of the two properties should #e &uaranteed #y the two copy functions>

Chapter //& Gesource -anagement 7. 0hat is a smart pointer> 10. 0hat is reference1countin&>

1 @6@ 1

11. Fealizin& that the copy constructor and assi&nment operator for most classes have several commonalities- you decide to implement a class's copy constructor usin& the class's assi&nment operator! 8or e)ample- you try implementin& the Je*tor's copy constructor as
tem$late t%$ename ;) Je*tor ;)44Je*tor(*onst Je*tor? other) { 3this = other; #

KSince this is a pointer to the receiver o#*ect- 3this is the receiver o#*ect- so 3this = other means to assi&n the receiver o#*ect the value of the parameter otherL This idea- while well1intentioned- has a serious flaw that causes the copy constructor to almost always cause a crash! 0hy is this> 5+int& 'ere any o$ the 3ector data members initiali8ed be$ore calling the assignment operator( 'al* through the assignment operator and see what happens i$ the receiver ob!ect)s data members haven)t been initiali8ed 6 12. 't is ille&al to write a copy constructor that accepts its parameter #y value! 0hy is this> /oweverit's perfectly accepta#le to have an assi&nment operator that accepts its parameter #y value! 0hy is this le&al> 0hy the difference> 13. ,n alternative implementation of the assi&nment operator uses a techni5ue called copy"and"swap! The copy1and1swap approach is #roken down into two steps! 8irst- we write a mem#er function that accepts a reference to another instance of the class- then e)chan&es the data mem#ers of the receiver o#*ect and the parameter! 8or e)ample- when workin& with the 9ebugJe*tor- we mi&ht write a function called s'a$2ith as follows=
tem$late t%$ename Elem;%$e) void Je*tor Elem;%$e)44s'a$2ith(Je*tor? other) { s'a$(arra%, other.arra%); s'a$(logi*al7ength, other.logi*al7ength); s'a$(allo*ated7ength, other.allo*ated7ength); #

/ere- we use the ST s'a$ al&orithm to e)chan&e data mem#ers! "otice that we never actually make a deep1copy of any of the elements in the array ( we simply swap pointers with the other 9ebugJe*tor! 0e can then implement the assi&nment operator as follows=
tem$late t%$ename ;) Je*tor ;)? Je*tor ;)44o$erator= (*onst Je*tor? other) { 9ebugJe*tor tem$(other); s'a$2ith(tem$); return 3this; #

Trace throu&h this implementation of the assi&nment operator and e)plain how it sets the receiver o#*ect to #e a deep1copy of the parameter! 0hat function actually deep1copies the data> 0hat function is responsi#le for cleanin& up the old data mem#ers>

1 @6A 1

Chapter //& Gesource -anagement

14. 0hen writin& an assi&nment operator usin& the pattern covered earlier in the chapter- we had to e)plicitly check for self1assi&nment in the #ody of the assi&nment operator! J)plain why this is no lon&er necessary usin& the copy1and1swap approach- #ut why it still mi&ht #e a &ood idea to insert the self1assi&nment check anyway! 1 . , sin&leton class is a class that can have at most one instance! Typically- a sin&leton class has its default constructor and destructor marked private so that clients cannot instantiate the class directly- and e)ports a stati* mem#er function called get(nstan*e() that returns a reference to the only instance of the class! That one instance is typically a private static data mem#er of the class! 8or e)ample=
*lass 6ingleton { $ubli*4 stati* 6ingleton? get(nstan*e(); $rivate4 6ingleton(); "" 5lients *annot *all this fun*tion; itAs $rivate c6ingleton(); "" ... nor *an the% *all this one stati* 6ingleton instan*e; "" ... but the% *an be used here be*ause "" instan*e is $art of the *lass.

#;

6ingleton 6ingleton44instan*e;

2oes it make sense for a sin&leton class to have a copy constructor or assi&nment operator> 'f soimplement them! 'f not- modify the 6ingleton interface so that they are disa#led! 1!. 3iven this chapter's description a#out how to disa#le copyin& in a class- implement a macro 9(6A77=2L5=<S(KG that accepts as a parameter the name of the current class such that if 9(6A77=2L5=<S(KG is placed into the private section of a class- that class is uncopya#le! "ote that it is le&al to create macros that span multiple lines #y endin& each line with the , character! 8or e)ample- the followin& is all one macro=
.define 5IEA;EL<I(K;EI(str) void <rint..str() {, *out .str endl;, #

1$. Consider the followin& alternative mechanism for disa#lin& copyin& in a class= instead of markin& those functions private- instead we implement those functions- #ut have them call abort Ka function from *stdlib) that immediately terminates the pro&ramL after printin& out an error messa&e! 8or e)ample=
*lass <seudo@n*o$%able { $ubli*4 <seudo@n*o$%able(*onst <seudo@n*o$%able? other) { abort(); # <seudo@n*o$%able? o$erator= (*onst <seudo@n*o$%able? other) { abort(); return 3this; "" Kever rea*hed; su$$resses *om$iler 'arnings # #;

0hy is this approach a #ad idea>

Chapter //& Gesource -anagement

1 @6? 1

16. Should you copy stati* data mem#ers in a copy constructor or assi&nment operator> 0hy or why not> 17. 'n the canonical implementation of the assi&nment operator we saw earlier in this chapter- we used the check if (this 1= ?other) to avoid pro#lems with self1assi&nment! 'n this e)ercisewe'll see what happens if we replace this check with if (3this 1= other)! 1. 0hat is the meanin& of if (3this 1= other)> 0ill this code compile for any class- or does that class have to have a special property> 2. 0ill the check if (3this 1= other) correctly detect whether an o#*ect is #ein& assi&ned to itself> 0ill it detect anythin& else> 3. ,ssume that the Je*tor has an implementation of o$erator1= that checks whether the operands have e)actly the same size and elements! 0hat is the asymptotic K#i&1GL comple)ity of the check if(3this 1= other)> /ow a#out if (this 1= ?other)> 2oes this &ive you a #etter sense why the latter is prefera#le to the former> 20. 'n a sense- our implementation of the Je*tor assi&nment operator is wasteful! 't works #y completely discardin& the internal array- then constructin& a new array to hold the other Je*tor's elements! ,n alternative implementation would work as follows! 'f the other Je*tor's elements can fit in the space currently allocated #y the Je*tor- then the elements from the other Je*tor are copied directly into the e)istin& space! Gtherwise- new space is allocated as #efore! Fewrite the Je*tor's o$erator= function usin& this optimization! 0hy won't this techni5ue work for the copy constructor>

C.a+ter 128 )rror 3andling


_________________________________________________________________________________________________________

Forty years ago, goto"laden code was considered per$ectly good practice Aow we strive to write structured control $lows Twenty years ago, globally accessible data was considered per$ectly good practice Aow we strive to encapsulate data Ten years ago, writing $unctions without thin*ing about the impact o$ e4ceptions was considered good practice Aow we strive to write e4ception"sa$e code Time goes on 'e live 'e learn ( Scott Beyers- author of E$$ective C++ and one of the leadin& e)perts on C++! NBey0?O 'n an ideal world- network connections would never fail- files would always e)ist and #e properly formatted- users would never type in malformed input- and computers would never run out of memory! Fealistically- thou&h- all of the a#ove can and will occur and your pro&rams will have to #e a#le to respond to them &racefully! 'n these scenarios- the normal function1call1and1return mechanism is not ro#ust enou&h to si&nal and report errors and you will have to rely on e4ception handling- a C++ lan&ua&e feature that redirects pro&ram control in case of emer&encies! J)ception handlin& is a comple) topic and will have far1reachin& effects on your C++ code! This chapter introduces the motivation underlyin& e)ception handlin&- #asic e)ception1handlin& synta)- and some advanced techni5ues that can keep your code operatin& smoothly in an e)ception1filled environment! A 6im+le !roblem Up to this point- all of the pro&rams you've written have proceeded linearly ( they #e&in inside a special function called main- then proceed throu&h a chain of function calls and returns until KhopefullyL hittin& the end of main! 0hile this is perfectly accepta#le- it rests on the fact that each function- &iven its parameters- can perform a meanin&ful task and return a meanin&ful value! /owever- in some cases this simply isn't possi#le! Suppose- for e)ample- that we'd like to write our own version of the CS1067HI 6tring;o(nteger function- which converts a string representation of an num#er into an int e5uivalent! Gne possi#le KpartialL implementation of 6tring;o(nteger mi&ht look like this=P
int 6tring;o(nteger(*onst string ?in$ut) { stringstream *onverter(in$ut); int result; "" ;r% reading an int, fail if 'eAre unable to do so. *onverter )) result; if (*onverter.fail()) // $hat should we do here! *har leftover; "" 6ee if an%thingAs left over. *onverter )) leftover; if (1*onverter.fail()) return result; else // $hat should we do here! (f so, fail.

P This is #ased off of the Get(nteger function we covered in the chapter on streams! 'nstead of loopin& and repromptin& the user for input at each step- however- it simply reports errors on failure!

1 @D0 1

Chapter /1& Error +andling

'f the parameter in$ut is a string with a valid inte&er representation- then this function simply needs to perform the conversion! 7ut what should our function do if the parameter doesn't represent an inte&er> Gne possi#le option- and the one used #y the CS1067HI implementation of 6tring;o(nteger- is to call a function like Error that prints an error and terminates the pro&ram! This response seems a #it drastic and is a decidedly su#optimal solution for several reasons! 8irst- callin& Error doesn't &ive the pro&ram a chance to recover from the pro#lem! 6tring;o(nteger is a simple utility function- not a critical infrastructure component- and if it fails chances are that there's an ele&ant way to deal with the pro#lem! 8or e)ample- if we're usin& 6tring;o(nteger to convert user input in a te)t #o) into an inte&er for further processin&- it makes far more sense to reprompt the user than to terminate the pro&ram! Secondin a very lar&e or complicated software system- it seems silly to terminate the pro&ram over a simple strin& error! 8or e)ample- if this 6tring;o(nteger function were used in an email client to convert a strin& representation of a time to an inte&er format Kparsin& the hours and minutes separatelyL- it would #e disastrous if the pro&ram crashed whenever receivin& malformed emails! 'n essence- while usin& a function like Error will prevent the pro&ram from continuin& with &ar#a&e values- it is simply too drastic a move to use in serious code! This approach su&&ests a second option- one common in pure C ( sentinel values! The idea is to have functions return special values meanin& 4this value indicates that the function failed to e)ecute correctly!6 'n our case- we mi&ht want to have 6tring;o(nteger return 11 to indicate an error- for e)ample! Compared with the 4drop everythin&6 approach of Error this may seem like a &ood option O it reports the error and &ives the callin& function a chance to respond! /owever- there are several ma*or pro#lems with this method! 8irst- in many cases it is not possi#le to set aside a value to indicate failure! 8or e)amplesuppose that we choose to reserve 11 as an error code for 6tring;o(nteger! 'n this case- we'd make all of our calls to 6tring;o(nteger as
if (6tring;o(nteger(m%<aram) == -8) { "3 ... handle error ... 3" #

7ut what happens if the input to 6tring;o(nteger is the strin& /-8/> 'n this case- whether or not the 6tring;o(nteger function completes successfully- it will still return 11 and our code mi&ht confuse it with an error case! ,nother serious pro#lem with this approach is that if each function that mi&ht possi#ly return an error has to reserve sentinel values for errors- we mi&ht accidentally check the return value of one function a&ainst the error code of another function! 'ma&ine if there were several constants floatin& around named EII=II 6;A;@6LEII=II (KJA7(9LIE6@7;- etc!- and whenever you called a function you needed to check the return value a&ainst the correct one of these choices! 'f you chose incorrectly- even with the #est of intentions your error1checkin& would #e invalid! .et another shortcomin& of this approach is that in some cases it will #e impossi#le to reserve a value for use as a sentinel! 8or e)ample- suppose that a function returns a ve*tor double)! 0hat special ve*tor double) should we choose to use as a sentinel> /owever- the most serious pro#lem with the a#ove approach is that you as a pro&rammer can i&nore the return value without encounterin& any warnin&s! Jven if 6tring;o(nteger returns a sentinel value indicatin& an error- there are no compile1time or runtime warnin&s if you choose not to check for a return value! 'n the case of 6tring;o(nteger this may not #e that much of a pro#lem ( after all- holdin& a sentinel value instead of a meanin&ful value will not immediately crash the pro&ram ( #ut this can lead to pro#lems down the line that can snow#all into fully1fled&ed crashes! 0orse- since the crash will pro#a#ly #e caused #y errors from far earlier in the code- these sorts of pro#lems can #e ni&htmarish to de#u&!

Chapter /1& Error +andling

1 @D1 1

Surprisin&ly- e)perience shows that many pro&rammers ( either out of ne&li&ence or laziness ( for&et to check return values for error codes and snow#all effects are rather common! 0e seem to have reached an unsolva#le pro#lem! 0e'd like an error1handlin& system that- like Errorprevents the pro&ram from continuin& normally when an error occurs! ,t the same time- however- we'd like the ele&ance of sentinel values so that we can appropriately process an error! /ow can we com#ine the stren&ths of #oth of these approaches into a sin&le system> )*ce+tion 3andling The reason the a#ove e)ample is such a pro#lem is that the normal C++ function1call1and1return system simply isn't ro#ust enou&h to communicate errors #ack to the callin& function! To resolve this pro#lemC++ provides lan&ua&e support for an error1messa&in& system called e4ception handling that completely #ypasses function1call1and1return! 'f an error occurs inside a function- rather than returnin& a value- you can report the pro#lem to the e)ception handlin& system to *ump to the proper error1handlin& code! The C++ e)ception handlin& system is #roken into three parts ( tr% #locks- *at*h #locks- and thro' statements! tr% #locks are simply re&ions of code desi&nated as areas that runtime errors mi&ht occur! To declare a tr% #lock- you simply write the keyword try- then surround the appropriate code in curly #races! 8or e)ample- the followin& code shows off a tr% #lock=
try { *out # /(Am in a tr% blo*B1/ endl;

'nside of a tr% #lock- code e)ecutes as normal and *umps to the code directly followin& the tr% #lock once finished! /owever- at some point inside a tr% #lock your pro&ram mi&ht run into a situation from which it cannot normally recover ( for e)ample- a call to 6tring;o(nteger with an invalid ar&ument! 0hen this occurs- you can report the error #y usin& the thro- keyword to 4throw6 the e)ception into the nearest matchin& *at*h clause! ike return- thro' accepts a sin&le parameter that indicates an o#*ect to throw so that when handlin& the e)ception your code has access to e)tra information a#out the error! 8or e)ample- here are three statements that each throw o#*ects of different types=
throw 0E throw new #ector2double:E throw 3.1)1*-E "" ;hro' an int "" ;hro' a ve*tor double) 3 "" ;hro' a double

0hen you throw an e)ception- it can #e cau&ht #y a *at*h clause specialized to catch that error! *at*h clauses are defined like this=
catch31arameter%ype param4 { "3 Error-handling *ode 3" #

Here, <arameter;%$e represents the type o* variable this *at*h cla#se is capable o* catchin/. *at*h #locks must directly follow tr% #locks- and it's ille&al to declare one without the other! Since catch clauses are specialized for a sin&le type- it's perfectly le&al to have cascadin& catch clauses- each desi&ned to pick up a different type of e)ception! 8or e)ample- here's code that catches e)ceptions of type int- ve*tor int)and string=

1 @D; 1

Chapter /1& Error +andling

tr% { "" 9o something # catch3int myInt4 { "" (f the *ode thro's an int, e+e*ution *ontinues here. # catch3const #ector2int:P myKector4 { "" =ther'ise, if the *ode thro's a ve*tor int), e+e*ution resumes here. # catch3const stringP myItring4 { "" 6ame for string #

"ow- if the code inside the tr% #lock throws an e)ception- control will pass to the correct *at*h #lock! .ou can visualize e)ception handlin& as a room of people and a #all! The code inside the tr% #lock #e&ins with the #all and continues talkin& as lon& as possi#le! 'f an error occurs- the tr% #lock throws the #all to the appropriate *at*h handler- which #e&ins e)ecutin&! et's return to our earlier e)ample with 6tring;o(nteger! 0e want to si&nal an error in case the user enters an invalid parameter- and to do so we'd like to use e)ception handlin&! The 5uestion- thou&h- is what type of o#*ect we should throw! 0hile we can choose whatever type of o#*ect we'd like- C++ provides a header file- stde+*e$t)- that defines several classes that let us specify what error tri&&ered the e)ception! Gne of these- invalidLargument- is ideal for the situation! invalidLargument accepts in its constructor a string parameter containin& a messa&e representin& what type of error occurred- and has a mem#er function called 'hat that returns what the error was! P 0e can thus rewrite the code for 6tring;o(nteger as
int 6tring;o(nteger(*onst string? in$ut) { stringstream *onverter(in$ut); int result; "" ;r% reading an int, fail if 'eAre unable to do so. *onverter )) result; if (*onverter.fail()) throw in#alid8argument3FHannot parse F D input D F as an integer.F4E *har leftover; "" 6ee if an%thingAs left over. (f so, fail. *onverter )) leftover; if (1*onverter.fail()) return result; else throw in#alid8argument3string3FNne5pected character" F4 D lefto#er4E

"otice that while the function itself does not contain a tr%H*at*h pair- it nonetheless has a thro' statement! 'f this statement is e)ecuted- then C++ will step #ackwards throu&h all callin& functions until it finds an appropriate *at*h statement! 'f it doesn't find one- then the pro&ram will halt with a runtime error! "ow- we can write code usin& 6tring;o(nteger that looks like this=

is a poor choice of a name for a mem#er function! Clease make sure to use more descriptive names in your codeR
'hat

Chapter /1& Error +andling


tr% { int result = 6tring;o(nteger(m%6tring); *out /;he result 'as4 / result; # *at*h(*onst invalidLargument? $roblem) { *out problem.what34 endl; "" <rints out the error message. # *out /Sa%1 2eAre done./ endl;

1 @D@ 1

/ere- if 6tring;o(nteger encounters an error and throws an e)ception- control will *ump out of the tr% #lock into the *at*h clause specialized to catch o#*ects of type invalidLargument! Gtherwise- code continues as normal in the tr% #lock- then skips over the *at*h clause to print 4.ayR 0e're done!6 There are several thin&s to note here! 8irst- if 6tring;o(nteger throws an e)ception- control immediately #reaks out of the tr% #lock and *umps to the *at*h clause! Unlike the pro#lems we had with our earlier approach to error handlin&- here- if there is a pro#lem in the tr% #lock- we're &uaranteed that the rest of the code in the tr% #lock will not e)ecute- preventin& runtime errors stemmin& from malformed o#*ects! Second- if there is an e)ception and control resumes in the *at*h clause- once the *at*h #lock finishes runnin&- control does not resume #ack inside the tr% #lock! 'nstead- control resumes directly followin& the tr%H*at*h pair- so the pro&ram a#ove will print out 4.ayR 0e're done!6 once the *at*h #lock finishes e)ecutin&! 0hile this mi&ht seem unusual- remem#er that the reason for e)ception handlin& in the first place is to halt code e)ecution in spots where no meanin&ful operation can #e defined! Thus if control leaves a tr% #lock- chances are that the rest of the code in the tr% could not complete without errors- so C++ does not provide a mechanism for resumin& pro&ram control! Third- note that we cau&ht the invalidLargument e)ception #y reference K*onst invalidLargument? instead of invalidLargumentL! ,s with parameter1passin&- e)ception1catchin& can take values either #y value or #y reference- and #y acceptin& the parameter #y reference you can avoid makin& an unnecessary copy of the thrown o#*ect! A 1ord on 6co+e J)ception handlin& is an essential part of the C++ pro&rammin& lan&ua&e #ecause it provides a system for recoverin& from serious errors! ,s its name implies- e)ception handlin& should #e used only for e4ceptional circumstances ( errors out of the ordinary that necessitate a ma*or chan&e in the flow of control! 0hile you can use e)ception handlin& as a fancy form of function call and return- it is hi&hly recommended that you avoid doin& so! Throwin& an e)ception is much slower than returnin& a value #ecause of the e)tra #ookkeepin& re5uired- so #e sure that you're only usin& e)ception handlin& for serious pro&ram errors! ,lso- the e)ception handlin& system will only respond when manually tri&&ered! Unless a code snippet e)plicitly thro's a value- a *at*h #lock cannot respond to it! This means that you cannot use e)ception handlin& to prevent your pro&ram from crashin& from se&mentation faults or other pointer1#ased errorssince pointer errors result in operatin&1system level process termination- not C++1level e)ception handlin&!P !rogramming wit. )*ce+tion 3andling 0hile e)ception handlin& is a ro#ust and ele&ant system- it has several sweepin& implications for C++ code! Bost nota#ly- when usin& e)ception handlin&- unless you are a#solutely certain that the classes and functions you use never throw e)ceptions- you must treat your code as thou&h it mi&ht throw an e)ception
P 'f you use Bicrosoft's Tisual Studio development environment- you mi&ht notice that various errors like null1 pointer dereferences and stack overflows result in errors that mention 4unhandled e)ception6 in their description! This is a Bicrosoft1specific feature and is different from C++'s e)ception1handlin& system!

1 @DA 1

Chapter /1& Error +andling

at any point! 'n other words- you can never assume that an entire code #lock will #e completed on its ownand should #e prepared to handle cases where control #reaks out of your functions at inopportune times! 8or e)ample- consider the followin& function=
void 6im$le&un*tion() { int3 m%Arra% = ne' int[8EF]; 9o6omething(m%Arra%); delete [] m%Arra%; #

/ere- we allocate space for a raw array- pass it to a function- then deallocate the memory! 0hile this code seems totally safe- when you introduce e)ceptions into the mi)- this code can #e very dan&erous! 0hat happens- for e)ample- if 9o6omething throws an e)ception> 'n this case- control would *ump to the nearest *at*h #lock and the line delete [] m%Arra% would never e)ecute! ,s a result- our pro&ram will leak the array! 'f this pro&ram runs over a sufficiently lon& period of time- eventually we will run out of memory and our pro&ram will crash! There are three main ways that we can avoid these pro#lems! 8irst- it's completely accepta#le to *ust avoid e)ception1handlin& all to&ether! This approach mi&ht seem like a cop1out- #ut it is a completely valid option that many C++ developers choose! Several ma*or software pro*ects written in C++ do not use e)ception handlin& Kincludin& the Bozilla 8irefo) we# #rowserL- partially #ecause of the e)tra difficulties encountered when usin& e)ceptions! /owever- this approach results in code that runs into the same pro#lems discussed earlier in this chapter with 6tring;o(nteger ( functions can only communicate errors throu&h return values and pro&rammers must #e e)tra vi&ilant to avoid i&norin& return values! The second approach to writin& e)ception1safe code uses a techni5ue called 4catch1and1rethrow!6 et's return to the a#ove code e)ample with a dynamically1allocated character #uffer! 0e'd like to &uarantee that the array we've allocated &ets deallocated- #ut as our code is currently written- it's difficult to do so #ecause the 9o6omething function mi&ht throw an e)ception and interrupt our code flow! 'f there is an e)ception- what if we were a#le to somehow intercept that e)ception- clean up the #uffer- and then propa&ate the e)ception outside of the 6im$le&un*tion function> 8rom an outside perspective- it would look as if the e)ception had come from inside the 9o6omething function- #ut in reality it would have taken a 5uick stop inside 6im$le&un*tion #efore proceedin& outwards! The reason this method works is that it is legal to throw an e4ception $rom inside a catch bloc*! ,lthou&h *at*h #locks are usually reserved for error handlin&- there is nothin& preventin& us from throwin& the e)ception we catch! 8or e)ample- this code is completely le&al=
tr%{ tr% { 9o6omething(); # *at*h(*onst invalidLargument? error) { *out /(nner blo*B4 Error4 / error.'hat() throw error; "" <ro$agate the error out'ard #

endl;

# *at*h(*onst invalidLargument? error) { *out /=uter blo*B4 Error4 / error.'hat() #

endl;

/ere- if the 9o6omething function throws an e)ception- it will first #e cau&ht #y the innermost tr% #lockwhich prints it to the screen! This *at*h handler then throws error a&ain- and this time it is cau&ht #y the outermost *at*h #lock!

Chapter /1& Error +andling

1 @D? 1

0ith this techni5ue- we can almost rewrite our 6im$le&un*tion function to look somethin& like this=
void 6im$le&un*tion() { int m%Arra% = ne' int[8EF]; "3 ;r% to 9o6omething. (f it fails, *at*h the e+*e$tion and rethro' it. 3" try { 9o6omething(m%56tring); # catch (/G $hat to catch! G/) { delete RS my.rrayE throw /G $hat to throw! G/E # "3 Kote that if there is no e+*e$tion, 'e still need to *lean things u$. 3" delete [] m%Arra%; #

There's a #it of a pro#lem here ( what sort of e)ceptions should we catch> Suppose that we know every sort of e)ception 9o6omething mi&ht throw! 0ould it #e a &ood idea to write a *at*h #lock for each one of these types> ,t first this may seem like a &ood idea- #ut it can actually cause more pro#lems than it solves! 8irst- in each of the *at*h #locks- we'd need to write the same delete [] statement! 'f we were to make chan&es to the 6im$le&un*tion function that necessitated more cleanup code- we'd need to make pro&ressively more chan&es to the 6im$le&un*tion *at*h cascade- increasin& the potential for errors! ,lso- if we for&et to catch a specific type of error- or if 9o6omething later chan&es to throw more types of errors- then we mi&ht miss an opportunity to catch the thrown e)ception and will leak resources! Clus- if we don't know what sorts of e)ceptions 9o6omething mi&ht throw- this entire approach will not work! The pro#lem is that in this case- we want to tell C++ to catch anything that's thrown as an e)ception! 0e don't care a#out what the type of the e)ception is- and need to intercept the e)ception simply to ensure that our resource &ets cleaned up! 8ortunately- C++ provides a mechanism specifically for this purpose! To catch an e)ception of any type- you can use the special synta) catch(... - which catches any e)ception! Thus we'll have the *at*h clause inside 9o6omething #e a *at*h(...) clause- so that we can catch any type of e)ception that 9o6omething mi&ht throw! 7ut this causes another pro#lem= we'd like to rethrow the e)ception- #ut since we've used a *at*h(...) clause- we don't have a name for the specific e)ception that's #een cau&ht! 8ortunately- C++ has a special use of the thro' statement that lets you throw the current e)ception that's #ein& processed! The synta) is
throwE

That is- a lone thro' statement with no parameters! 7e careful when usin& thro';- however- since if you're not inside of a *at*h #lock the pro&ram will crashR The final version of 6im$le&un*tion thus looks like this=

1 @D6 1
void 6im$le&un*tion() { int m%Arra% = ne' int[8EF];

Chapter /1& Error +andling

"3 ;r% to 9o6omething. (f it fails, *at*h the e+*e$tion and rethro' it. 3" try { 9o6omething(m%56tring); # catch (...) { delete RS my.rrayE throwE # "3 Kote that if there is no e+*e$tion, 'e still need to *lean things u$. 3" delete [] m%Arra%; #

,s you can tell- the 4catch1and1rethrow6 approach to e)ception handlin& results in code that can #e rather complicated! 0hile in some circumstances catch1and1rethrow is the #est option- in many cases there's a much #etter alternative that results in concise- reada#le- and thorou&hly e)ception1safe code ( o#*ect memory mana&ement! $b%ect (emor/ (anagement and 4AII C++'s memory model is #est descri#ed as 4dan&erously efficient!6 Unlike other lan&ua&es like $ava- C++ does not have a &ar#a&e collector and conse5uently you must manually allocate and deallocate memory! ,t first- this mi&ht seem like a simple task ( *ust delete anythin& you allocate with ne'- and make sure not to delete somethin& twice! /owever- it can #e 5uite difficult to keep track of all of the memory you've allocated in a pro&ram! ,fter all- you pro#a#ly won't notice any symptoms of memory leaks unless you run your pro&rams for hours on end- and in all likelihood will have to use a special tool to check memory usa&e! .ou can also run into trou#le where two o#*ects each point to a shared o#*ect! 'f one of the o#*ects isn't careful and accidentally deletes the memory while the other one is still accessin& it- you can &et some particularly nasty runtime errors where seemin&ly valid data has #een corrupted! The situation &ets all the more complicated when you introduce e)ception1handlin& into the mi)- where the code to delete allocated memory mi&ht not #e reached #ecause of an e)ception! 'n some cases havin& a hi&h de&ree of control over memory mana&ement can #e 5uite a #oon to your pro&rammin&- #ut much of the time it's simply a hassle! 0hat if we could somehow &et C++ to mana&e our memory for us> 0hile #uildin& a fully1functional &ar#a&e collection system in C++ would #e *ust short of impossi#le- usin& only #asic C++ concepts it's possi#le to construct an e)cellent appro)imation of automatic memory mana&ement! The trick is to #uild smart pointers- o#*ects that ac5uire a resource when created and that clean up the resource when destroyed! That is- when the o#*ects are constructed- they wrap a newly1allocated pointer inside an o#*ect shell that cleans up the mess when the o#*ect &oes out of scope! Com#ined with features like operator overloadin&- it's possi#le to create slick smart pointers that look almost e)actly like true C++ pointers- #ut that know when to free unused memory! The C++ header file memor%) e)ports the autoL$tr type- a smart pointer that accepts in its constructor a pointer to dynamically1allocated memory and whose constructor calls delete on the resource!P autoL$tr is a template class whose template parameter indicates what type of o#*ect the autoL$tr will 4point6 at! 8or e)ample- an autoL$tr string) is a smart pointer that points to a string! 7e careful ( if you write autoL$tr string 3)- you'll end up with an autoL$tr that points to a string 3- which is similar to a string 33! Throu&h the ma&ic of operator overloadin&- you can use the re&ular dereference and arrow operators on an autoL$tr as thou&h it were a re&ular pointer! 8or e)ample- here's some code
P "ote that autoL$tr calls delete- not delete []- so you cannot store dynamically1allocated arrays in you want the functionality of an array with automatic memory mana&ement- use a ve*tor!
autoL$tr!

'f

Chapter /1& Error +andling

1 @DD 1

that dynamically allocates a ve*tor int)- stores it in an autoL$tr- and then adds an element into the ve*tor=
"3 0ave the autoL$tr $oint to a ne'l%-allo*ated ve*tor int). ;he *onstru*tor 3 is e+$li*it, so 'e must use $arentheses. 3" auto8ptr2#ector2int: : managedKector3new #ector2int:4E managedKector-:$ushLba*B(8CD); "" Add 8CD to the end of the ve*tor. (GmanagedKector)[0] = GE; "" 6et element 0 b% dereferen*ing the $ointer.

0hile in many aspects autoL$tr acts like a re&ular pointer with automatic deallocation- autoL$tr is fundamentally different from re&ular pointers in assi&nment and initialization! Unlike o#*ects you've encountered up to this point- assi&nin& or initializin& an autoL$tr to hold the contents of another destructively modi$ies the source autoL$tr! Consider the followin& code snippet=
autoL$tr int) one(ne' int); autoL$tr int) t'o; t'o = one;

,fter the final line e)ecutes- t'o will hold the resource ori&inally owned #y one- and one will #e empty! 2urin& the assi&nment- one relin5uished ownership of the resource and cleared out its state! Conse5uently- if you use one from this point forward- you'll run into trou#le #ecause it's not actually holdin& a pointer to anythin&! 0hile this is hi&hly counterintuitive- it has several advanta&es! 8irst- it ensures that there can #e at most one autoL$tr to a resource- which means that you don't have to worry a#out the contents of an autoL$tr #ein& cleaned up out from underneath you #y another autoL$tr to that resource! Second- it means that it's safe to return autoL$trs from functions without the resource &ettin& cleaned up! 0hen returnin& an autoL$tr from a function- the ori&inal copy of the autoL$tr will transfer ownership to the new autoL$tr durin& return1value initialization- and the resource will #e transferred safely!P 8inally- #ecause each autoL$tr can assume that it has sole ownership of the resourceautoL$tr can #e implemented e)tremely efficiently and has almost zero overhead! ,s a conse5uence of the 4 autoL$tr assi&nment is transference6 policy- you must #e careful when passin& an autoL$tr #y value to a function! Since the parameter will #e initialized to the ori&inal o#*ect- it will empty the ori&inal autoL$tr! Similarly- you should not store autoL$trs in ST containers- since when the containers reallocate or #alance themselves #ehind the scenes they mi&ht assi&n autoL$trs around in a way that will tri&&er the o#*ect destructors! 8or reference- here's a list of the mem#er functions of the autoL$tr template class=

P 8or those of you interested in pro&rammin& lan&ua&e desi&n- C++ uses what's known as copy semantics for most of its operations- where assi&nin& o#*ects to one another creates copies of the ori&inal o#*ects! autoL$tr seems stran&e #ecause it uses move semantics- where assi&nin& autoL$trs to one another transfers ownership of some resource! Bove semantics are not easily e)pressed in C++ and the code to correctly implement autoL$tr is surprisin&ly comple) and re5uires an intricate understandin& of the C++ lan&ua&e! The ne)t revision of C++- C+ +0)- will add several new features to the lan&ua&e to formalize and simply move semantics and will replace autoL$tr with uni[ueL$tr- which formalizes the move semantics!

1 @DE 1
e+$li*it autoL$tr (;%$e3 resour*e) autoL$tr int) $tr(ne' int);

Chapter /1& Error +andling

Constructs a new autoL$tr wrappin& the specified pointer- which must #e from dynamically1allocated memory!
autoL$tr(autoL$tr? other) autoL$tr int) one(ne' int); autoL$tr int) t'o = one;

Constructs a new autoL$tr that ac5uires resource ownership from the autoL$tr used in the initialization! ,fterwards- the old autoL$tr will not encapsulate any dynamically1allocated memory!
;? o$erator 3() *onst 3m%Auto<tr = 8CD;

2ereferences the stored pointer and returns a reference to the memory it's pointin& at!
;3 o$erator-) () *onst m%6tringAuto<tr-)a$$end(/5!!1/);

Feferences mem#er functions of the stored pointer!


;3 release() int 3regular<tr = m%<tr.release();

Felin5uishes control of the stored resource and returns it so it can #e stored in another location! The autoL$tr will then contain a K@77 pointer and will not mana&e the memory any more!
void reset(;3 $tr = K@77) m%<tr.reset(); m%<tr.reset(ne' int);

Feleases any stored resources and optionally stores a new resource inside the autoL$tr!
;3 get() *onst 6ome&un*tion(m%<tr.get()); "" Ietrieve stored resour*e

<et#rns the stored pointer. reso#rce to other *#nctions.

@se*#l *or passin/ the mana/ed

Gf course- dynamically1allocated memory isn't the only C++ resource that can #enefit from o#*ect memory mana&ement! 8or e)ample- when workin& with GS1specific li#raries like Bicrosoft's 0in@; li#rary- you will commonly have to manually mana&e handles to system resources! 'n spots like these- writin& wrapper classes that act like autoL$tr #ut that do cleanup usin& methods other than a plain delete can #e 5uite #eneficial! 'n fact- the system of havin& o#*ects mana&e resources throu&h their constructors and destructors is commonly referred to as resource ac@uisition is initiali8ation- or simply F,''! )*ce+tions and 6mart !ointers Up to this point- smart pointers mi&ht seem like a curiosity- or perhaps a useful construct in a limited num#er of circumstances! /owever- when you introduce e)ception handlin& to the mi)- smart pointers will #e invalua#le! 'n fact- in professional code where e)ceptions can #e thrown at almost any point- smart pointers are almost as u#i5uitous as re&ular C++ pointers! et's suppose you're &iven the followin& linked list cell struct=
stru*t node; { int data; node; 3ne+t; #;

Chapter /1& Error +andling "ow- consider this function=


node;3 GetKe'5ell() { node;3 ne'5ell = ne' node;; ne'5ell-)ne+t = K@77; ne'5ell-)data = 6ome5om$li*ated&un*tion(); return ne'5ell; #

1 @D< 1

This function allocates a new node; cell- then tells it to hold on to the value returned #y 6ome5om$li*ated&un*tion! 'f we i&nore e)ception handlin&- this code is totally fine- provided of course that the callin& function correctly holds on to the node; 3 pointer we return! /owever- when we add e)ception handlin& to the mi)- this function is a recipe for disaster! 0hat happens if 6ome5om$li*ated&un*tion throws an e)ception> Since GetKe'5ell doesn't have an associated tr% #lock- the pro&ram will a#ort GetKe'5ell and search for the nearest *at*h clause! Gnce the *at*h finishes e)ecutin&- we have a pro#lem ( we allocated a node; o#*ect- #ut we didn't clean it up! 0orsesince GetKe'5ell is no lon&er runnin&- we've lost track of the node; entirely- and the memory is orphaned! Jnter autoL$tr to save the day! Suppose we chan&e the declaration node;3 ne'5ell to autoL$tr node;) ne'5ell! "ow- if 6ome5om$li*ated&un*tion throws an e)ception- we won't leak any memory since when the autoL$tr &oes out of scope- it will reclaim the memory for us! 0onderfulR Gf course- we also need to chan&e the last line from return ne'5ell to return ne'5ell.release()since we promised to return a node; 3- not an autoL$tr node;)! The new code is printed #elow=
node;3 GetKe'5ell() { auto8ptr2node%: newHell3new node%4E ne'5ell-)ne+t = K@77; ne'5ell-)data = 6ome5om$li*ated&un*tion(); return newHell.release34; "" ;ell the autoL$tr to sto$ managing memor%. #

This function is now wonderfully e)ception1safe thanks to autoL$tr! Jven if we prematurely e)it the function from an e)ception in 6ome5om$li*ated&un*tion- the autoL$tr destructor will ensure that our resources are cleaned up! /owever- we can make this code even safer #y usin& the autoL$tr in yet another spot! 0hat happens if we call GetKe'5ell #ut don't store the return value anywhere> 8or e)ample- suppose we have a function like this=
void 6ill%&un*tion() { GetKe'5ell(); "" =h dear, there goes the return value. #

0hen we wrote GetKe'5ell- we tacitly assumed that the callin& function would hold on to the return value and clean the memory up at some later point! /owever- it's totally le&al to write code like 6ill%&un*tion that calls GetKe'5ell and entirely discards the return value! This leads to memory leaks- the very pro#lem we were tryin& to solve earlier! 8ortunately- throu&h some creative use of autoL$tr- we can eliminate this pro#lem! Consider this modified version of GetKe'5ell=
auto8ptr2node%: GetKe'5ell() { autoL$tr node;) ne'5ell(ne' node;); ne'5ell-)ne+t = K@77; ne'5ell-)data = 6ome5om$li*ated&un*tion(); return ne'5ell; "" 6ee belo' #

1 @E0 1

Chapter /1& Error +andling

/ere- the function returns an autoL$tr- which means that the returned value is itself mana&ed! "ow- if we call 6ill%&un*tion- even thou&h we didn't &ra# the return value of GetKe'5ell- #ecause GetKe'5ell returns an autoL$tr- the memory will still &et cleaned up! Documenting In;ariants wit. assert The e)ception1handlin& techni5ues we've covered so far are e)cellent ways of handlin& and recoverin& from errors that can only #e detected at compile1time! 'f a network connection fails to open- or your &raphics card fails to initialize correctly- you can use e)ceptions to report the error so that your pro&ram can detect and recover from the pro#lem! /owever- there is an entirely different class of pro#lems that your pro&rams mi&ht encounter at runtime ( lo&ic errors! ,s much as we'd all like to think that we can write perfect software on the first try- we all make mistakes when desi&nin& pro&rams! 0e pass K@77 pointers into functions that e)pect them to #e non1K@77! 0e make accidental chan&es to linked lists while iteratin& over them! 0e pass in values #y reference that we meant to pass in #y value! These are normal errors in the pro&rammin& process- and while time and e)perience can reduce their fre5uency- they can never entirely #e eliminated! The 5uestion then arises ( &iven that you are &oin& to make mistakes durin& development- how can you desi&n your software to make it easier to detect and correct these errors> 0hen desi&nin& software- at various points in the pro&ram you will e)pect certain conditions to hold true! .ou mi&ht e)pect that a certain inte&er is even- or that a pointer is non1 K@77- etc! 'f these conditions don't hold- it's often a si&n that your pro&ram contains a #u&! Gne trick you can use to make it easier to detect and dia&nose #u&s is to have the pro&ram check that these invariants hold at runtime! 'f they do- then everythin& is &oin& accordin& to plan- #ut if for some reason the invariants do not hold it could si&nal the presence of a #u&! 'f the pro&ram can then report that an invariant failed to hold- it will make it si&nificantly easier to de#u&! 8or this purpose- C++ provides the assert macro! assert- e)ported #y the header *assert)- checks to see that some condition holds true! 'f so- the macro has no effect! Gtherwise- it prints out the statement that did not evaluate to true- alon& with the file and line num#er in which it was written- then terminates the pro&ram! 8or e)ample- consider the followin& code=
void :%&un*tion(int 3m%<tr) { assert3my1tr !O @NJJ4E 3m%<tr = 8CD; #

'f a caller passes a null pointer into :%&un*tion- the assert statement will halt the pro&ram and print out a messa&e that mi&ht look somethin& like this=
.ssertion ?ailed" Tmy1tr !O @NJJT" ?ile" main.cpp0 Jine" )(

7ecause assert a#ruptly terminates the pro&ram without &ivin& the rest of the application a chance to respond- you should not use assert as a &eneral1purpose error1handlin& routine! 'n practical software development- assert is usually used to e)press pro&rammer assumptions a#out the state of e)ecution that can only #e #roken if the software is written incorrectly! 'f an assert fails- it means that the pro&rammer made a mistake- not that somethin& unusual occurred at runtime! 8or errors that mi&ht arise durin& normal e)ecution- such as missin& files or malformed user input- user e)ception handlin&! 8or errors that represent a #u& in the ori&inal code- assert is a much #etter choice!

Chapter /1& Error +andling

1 @E1 1

et's consider a concrete e)ample! ,ssume we have some enumerated type 5olor- which mi&ht look like this=
enum 5olor {Ied, Green, Plue, :agenta, 5%an, Sello', Pla*B, 2hite#;

"ow- suppose that we want to write a function called (s<rimar%5olor that takes in a 5olor and reports whether that color is a primary color Kred- &reen- or #lueL! /ere's one implementation=
bool (s<rimar%5olor(5olor *) { s'it*h(*) { *ase Ied4 *ase Green4 *ase Plue4 return true; default4 "3 =ther'ise, must not be a $rimar% *olor. 3" return false; # #

/ere- if the color is Ied- Green- or Plue- we return that the color is indeed a primary color! Gtherwise- we return that it is not a primary color! /owever- what happens if the parameter is not a valid 5olor- perhaps if the call is (s<rimar%5olor(5olor(-8))> 'n this function- since we assume that that the parameter is indeed a color- we mi&ht want to indicate that to the pro&ram #y e)plicitly puttin& in an assert test! /ere's a modified version of the function- usin& assert and assumin& the e)istence of a function (s5olor=
bool (s<rimar%5olor(5olor *) { assert3IsHolor3c44E "" 2e assume that this is reall% a *olor. s'it*h (*) { *ase Ied4 *ase Green4 *ase Plue4 return true; default4 "3 =ther'ise, must not be a $rimar% *olor. 3" return false; # #

"ow- if the caller passes in an invalid 5olor- the pro&ram will halt with an assertion error pointin& us to the line that caused the pro#lem! 'f we have a &ood de#u&&er- we should #e a#le to fi&ure out which caller erroneously passed in an invalid Color and can #etter remedy the pro#lem! 0ere we to i&nore this case entirely- we mi&ht have considera#ly more trou#le de#u&&in& the error- since we would have no indication of where the pro#lem ori&inated! 0hile assert can #e used to catch a &ood num#er of pro&rammer errors durin& development- it has the unfortunate side1effect of slowin& a pro&ram down at runtime #ecause of the overhead of the e)tra checkin& involved! Conse5uently- most ma*or compilers disa#le the assert macro in release or optimized #uilds! This may seem dan&erous- since it eliminates checks for inconsistent state- #ut is actually not a pro#lem #ecause- in theory- you shouldn't #e compilin& a release #uild of your pro&ram if assert statements fail durin& e)ecution!P 7ecause assert is entirely disa#led in optimized #uilds- you should use assert only to check that specific relations hold true- never to check the return value of a function! 'f an assert contains a call to a function- when assert is disa#led in release #uilds- the function won't #e calledP 'n practice- this isn't always the case! 7ut it's still a nice theoryR

1 @E; 1

Chapter /1& Error +andling

leadin& to different #ehavior in de#u& and release #uilds! This is a persistent source of de#u&&in& headaches!

Chapter /1& Error +andling (ore to )*+lore

1 @E@ 1

J)ception1handlin& and F,'' are comple) topics that have impressive ramifications for the way that your write C++ code! /owever- we simply don't have time to cover every facet of e)ception handlin&! 'n case you're interested in e)plorin& more advanced topics in e)ception handlin& and F,''- consider lookin& into the followin&= 1. T.e 6tandard )*ce+tion Classes= 'n this chapter we discussed invalidLargument- one of the many e)ception classes availa#le in the C++ standard li#rary! /owever- there are several more e)ception classes that form an ela#orate hierarchy! Consider readin& into some of the other classes ( some of them even show up in the ST R 2. )*ce+tion 6+ecifications! 7ecause functions can throw e)ceptions at any time- it can #e difficult to determine which pieces of code can and cannot throw e)ceptions! 8ortunately- C++ has a feature called an e4ception speci$ication which indicates what sorts of e)ceptions a function is allowed to throw! 0hen an e)ception leaves a function with an e)ception specification- the pro&ram will a#ort unless the type of the e)ception is one of the types mentioned in the specification! 3. 2unction try Blocks! There is a variant of a re&ular try #lock that lets you put the entire contents of a function into a tryHcatch handler pair! /owever- it is a relatively new feature in C++ and is not supported #y several popular compilers! Check a reference for more information! 4. new and )*ce+tions! 'f your pro&ram runs out of availa#le memory- the ne' operator will indicate a failure #y throwin& an e)ception of type badLallo*! 0hen desi&nin& custom container classesit mi&ht #e worth checkin& a&ainst this case and actin& accordin&ly! . T.e Boost 6mart !ointers= 0hile autoL$tr is useful in a wide variety of circumstances- in many aspects it is limited! Gnly one autoL$tr can point to a resource at a time- and autoL$trs cannot #e stored inside of ST containers! The 7oost C++ li#raries conse5uently provide a hu&e num#er of smart pointers- many of which employ considera#ly more complicated resource1mana&ement systems than autoL$tr! Since many of these smart pointers are likely to #e included in the ne)t revision of the C++ standard- you should #e sure to read into them! 7*arne Stroustrup Kthe inventor of C++L wrote an e)cellent introduction to e)ception safety- focusin& mostly on implementations of the C++ Standard i#rary! 'f you want to read into e)ception1safe code- you can read it online at http=HHwww!research!att!comHd#sH@rd[safe!pdf! ,dditionally- there is a most e)cellent reference on autoL$tr availa#le at http=HHwww!&otw!caHpu#licationsHusin&[auto[ptr[effectively!htm that is a &reat resource on the su#*ect! !ractice !roblems 1. J)plain why the autoL$tr constructor is marked e+$li*it! 5+int& 0ive an e4ample o$ an error you can ma*e i$ the constructor is not mar*ed explicit6 2. The 6im$le&un*tion function from earlier in this chapter ran into difficulty with e)ception1safety #ecause it relied on a manually1mana&ed C strin&! J)plain why this would not #e a pro#lem if it instead used a C++ string!

1 @EA 1 3. Consider the followin& C++ function=


void :ani$ulate6ta*B(sta*B string)? m%6ta*B) { if (m%6ta*B.em$t%()) thro' invalidLargument(/Em$t% sta*B1/); string to$Elem = m%6ta*B.to$(); m%6ta*B.$o$(); "3 ;his might thro' an e+*e$tion1 3" 9o6omething(m%6ta*B); # m%6ta*B.$ush(to$Elem);

Chapter /1& Error +andling

This function accepts as input a C++ sta*B string)- pops off the top element- calls the 9o6omething function- then pushes the element #ack on top! Crovided that the 9o6omething function doesn't throw an e)ception- this code will &uarantee that the top element of the sta*B does not chan&e #efore and after the function e)ecutes! Suppose- however- that we wanted to a#solutely &uarantee that the top element of the stack never chan&es- even if the function throws an e)ception! Usin& the catch1and1rethrow strate&y- e)plain how to make this the case! . 0rite a class called Automati*6ta*B:anager whose constructor accepts a sta*B string) and pops off the top element Kif one e)istsL and whose destructor pushes the element #ack onto the sta*B! Usin& this class- rewrite the code in Cro#lem A so that it's e)ception safe! /ow does this version of the code compare to the approach usin& catch1and1rethrow>

!art T.ree
eneric !rogramming

C.a+ter 138 2unctors


_________________________________________________________________________________________________________

Consider a simple task! Suppose you have a ve*tor string) and you'd like to count the num#er of strings that have len&th less than five! .ou stum#le upon the ST *ountLif al&orithm- which accepts a ran&e of iterators and a predicate function- then returns the num#er of elements in the ran&e for which the function returns true! 8or e)ample- you could use *ountLif as follows to count the num#er of even inte&ers in a ve*tor=
bool (sEven(int val) { return val \ E == 0; # ve*tor int) m%Je*tor = "3 ... 3" int numEvens = *ountLif(m%Je*tor.begin(), m%Je*tor.end(), (sEven);

'n our case- since we want to count the num#er of strin&s with len&th less than five- we could write a function like this one=
bool 7ength(s7ess;han&ive(*onst string? str) { return str.length() H; #

,nd then call *ountLif(m%Je*tor.begin(), m%Je*tor.end(), 7ength(s7ess;han&ive) to &et the num#er of short strin&s in the ve*tor! Similarly- if we want to count the num#er of strin&s with len&th less than ten- we could write a 7ength(s7ess;han;en function like this one=
bool 7ength(s7ess;han;en(*onst string? str) { return str.length() 80; #

and then call *ountLif(m%Je*tor.begin(), m%Je*tor.end(), 7ength(s7ess;han;en)! 'n &eneralif we know in advance what len&th we want to compare the strin& len&ths a&ainst- we can write a function that returns whether a particular strin&'s len&th is less than that value- then pass it into *ountLif to &et our result! This approach is le&al C++- #ut is not particularly ele&ant! Jvery time we want to compare the strin& len&th a&ainst a particular value- we have to write an entirely new function to perform the comparison! 3ood pro&rammin& practice su&&ests that we should instead *ust write one function that looks like this=
bool 7ength(s7ess;han(*onst string? str0 siUeLt length) { return str.length() length; #

This more &eneric function takes in a strin& and a len&th- then returns whether the strin&'s len&th is less than the re5uested len&th! This way- we can specify the ma)imum len&th as the second parameter rather than writin& multiple instances of similar functions! 0hile this new function is more &eneric than the previous version- unfortunately we can't use it in con*unction with *ountLif! *ountLif re5uires a unary function Ka function takin& only one ar&umentL as its final parameter- and the new 7ength(s7ess;han is a binary function! Gur new 7ength(s7ess;han function- while more &eneric than the ori&inal version- is actually less use$ul in this conte)t! There must #e some way to compromise #etween the two approaches! 0e need a way to construct a function that takes

1 @EE 1

Chapter /3& Functors

in only one parameter Kthe strin& to testL- #ut which can #e customized to accept an ar#itrary ma)imum len&th! /ow can we do this> This pro#lem #oils down to a 5uestion of data flow! To construct this hy#rid function- we need to somehow communicate the upper #ound into the function so that it can perform the comparison! So how can we &ive this data to the function> Fecall that a function has access the followin& information= 'ts local varia#les! 'ts parameters! 3lo#al varia#les!

's there some way that we can store the ma)imum len&th of the strin& in one of these locations> 0e can't store it in a local varia#le- since local varia#les don't persist #etween function calls and aren't accessi#le to callers! ,s mentioned a#ove- we also can't store it in a parameter- since *ountLif is hardcoded to accept a unary function! That leaves &lo#al varia#les! 0e could solve this pro#lem usin& &lo#al varia#les= we would store the ma)imum len&th in a &lo#al varia#le- then compare the strin& parameter len&th a&ainst the &lo#al! 8or e)ample=
siUeLt g:a+7engthE "" Jalue to *om$are against bool 7ength(s7ess;han(*onst string? str) { return str.length() g:a+7ength; #

This approach works= if our ve*tor string) is called v- then we can count the num#er of elements less than some value #y writin&
g:a+7ength = "3 ... some value ... 3" int num6hort = *ountLif(v.begin(), v.end(), 7ength(s7ess;han);

7ut *ust #ecause this approach works does not mean that it is optimal! This approach is deeply flawed for several reasons- a handful of which are listed here= It is error&+rone! 7efore we use 7ength(s7ess;han- we must take care to set g:a+7ength to the ma)imum desired len&th! 'f we for&et to do so- then 7ength(s7ess;han will use the wron& value in the comparison and we will &et the wron& answer! Boreover- #ecause there is no formal relationship #etween the g:a+7ength varia#le and the 7ength(s7ess;han function- the compiler can't verify that we correctly set g:a+7ength #efore callin& 7ength(s7ess;han- puttin& an e)tra #urden on the pro&rammer It is not scalable! 'f every time we encounter a pro#lem like this one we create a new &lo#al varia#le- pro&rams we write will #e&in to fill up with &lo#al varia#les that are used only in the conte)t of a sin&le function! This leads to namespace pollution- where too many varia#les are in scope and it is easy to accidentally use one when another is e)pected! It uses global ;ariables! ,ny use of &lo#al varia#les should send a shiver runnin& down your spine! 3lo#al varia#les should #e avoided at all costs- and the fact that we're usin& them here su&&ests that somethin& is wron& with this setup!

"one of the options we've considered are feasi#le or attractive! There has to #e a #etter way to solve this#ut how>

Chapter /3& Functors 2unctors to t.e 4escue

1 @E< 1

The fundamental issue at heart here is that a unary function does not have access to enou&h information to answer the 5uestion we're askin&! Jssentially- we want a unary function to act like a #inary function without takin& an e)tra parameter! Usin& only the tools we've seen so far- this simply isn't possi#le! To solve this pro#lem- we'll turn to a more powerful C++ entity= a $unctor! , functor Kor $unction ob!ectL is an C++ class that acts like a function! 8unctors can #e called usin& the familiar function call synta)- and can yield values and accept parameters *ust like re&ular functions! 8or e)ample- suppose we create a functor class called :%5lass imitatin& a function acceptin& an int and returnin& a double! Then we could 4call6 an o#*ect of type :%5lass as follows=
:%5lass m%&un*tor; *out m%&un*tor(8CD) endl; "" /5all/ m%&un*tor 'ith $arameter 8CD

,lthou&h m%&un*tor is an o#*ect- in the second line of code we treat it as thou&h it were a function #y invokin& it with the parameter 1@D! ,t this point- functors mi&ht seem utterly #afflin&= why would you ever want to create an o#*ect that #ehaves like a function> 2on't worry- we'll answer that 5uestion in a short while! 'n the meantime- we'll discuss the synta) for functors and &ive a few motivatin& e)amples! To create a functor- we create an o#*ect that overloads the function call operator- o$erator ()! The name of this function is a #it misleadin& ( it is a function called o$erator ()- not a function called o$erator that takes no parameters! 2espite the fact that the name looks like 4operator parentheses-6 we're not redefinin& what it means to parenthesize the o#*ect! 'nstead- we're definin& a function that &ets called if we invoke the o#*ect like a function! Thus in the a#ove code*out m%&un*tor(8CD) endl;

is e5uivalent to
*out m%&un*tor.o$erator()(8CD) endl;

Unlike other operators we've seen so far- when overloadin& the function call operator- you're free to return an o#*ect of any type Kor even voidL and can accept any num#er of parameters! Femem#er that the point of operator overloadin& is to allow o#*ects to act like #uilt1in types- and since a re&ular function can have ar#itrarily many parameters and any return type- functors are allowed the same freedom! 8or e)amplehere's a sample functor that overloads the function call operator to print out a strin&=
*lass :%&un*tor { $ubli*4 void o$erator() (*onst string? str) *onst { *out str endl; # #;

"ote that in the function definition there are two sets of parentheses! The first &roup is for the function name ( o$erator () ( and the second for the parameters to o$erator ()! 'f we separated the implementation of o$erator () from the class definition- it would look like this=

1 @<0 1
*lass :%&un*tor { $ubli*4 void o$erator() (*onst string? str) *onst; #; void :%&un*tor44o$erator() (*onst string? str) *onst { *out str endl; #

Chapter /3& Functors

"ow that we've written :%&un*tor- we can use it as follows=


:%&un*tor fun*tor; fun*tor(/&un*tor $o'er1/);

This code calls the functor and prints out 48unctor powerR6 ,t this point functors mi&ht seem like little more than a curiosity! 4Sure-6 you mi&ht say- 4' can make an o#*ect that can #e called like a function! 7ut what does it #uy me>6 , lot more than you mi&ht initially suspect- it turns out! The key difference #etween a function and a functor is that a functor's function call operator is a member $unction whereas a raw C++ function is a $ree $unction! This means that a functor can access the followin& information when #ein& called= 'ts local varia#les! 'ts parameters! 3lo#al varia#les! Class data members!

This last point is e)tremely important and is the key difference #etween a re&ular function and a functor! 'f a functor's o$erator() mem#er function re5uires access to data #eyond what can #e communicated #y its parameters- we can store that information as a data mem#er inside the functor class! Since o$erator() is a mem#er of the functor class- it can then access that data freely! 8or e)ample- consider the followin& functor class=
*lass 6tringA$$ender { $ubli*4 "3 5onstru*tor taBes and stores a string. 3" e+$li*it 6tringA$$ender(*onst string? str) 4 toA$$end(str) {# "3 o$erator() $rints out a string, $lus the stored suffi+. 3" void o$erator() (*onst string? str) *onst { *out str A A toA$$end endl; # $rivate4 *onst string toA$$end; #;

This functor's constructor takes in a strin& and stores it for later use! 'ts o$erator () function accepts a strin&- then prints that strin& suffi)ed with the strin& stored #y the constructor! 0e can then use the 6tringA$$ender functor like this=
6tringA$$ender m%&un*tor(/is a'esome/); m%&un*tor(/5!!/);

Chapter /3& Functors

1 @<1 1

This code will print out 4C++ is awesome-6 since the constructor stored the strin& 4is awesome6 and we passed 4C++6 as a parameter to the function! 'f you'll notice- thou&h- in the actual function call we only passed in one piece of information ( the strin& 4C++!6 This is precisely why functors are so useful! ike re&ular functions- functors are invoked with a fi)ed num#er of parameters! Unlike raw functions- howeverfunctors can #e constructed to store as much information is necessary to solve the task at hand! et's return to the a#ove e)ample with *ountLif! Somehow we need to provide a unary function that can return whether a strin& is less than an ar#itrary len&th! To solve this pro#lem- instead of writin& a unary function- we'll create a unary $unctor whose constructor stores the ma)imum len&th and whose o$erator () accepts a strin& and returns whether it's of the correct len&th! /ere's one possi#le implementation=
*lass 6horter;han { $ubli*4 "3 A**e$t and store an int $arameter 3" e+$li*it 6horter;han(siUeLt ma+7ength) 4 length(ma+7ength) {# "3 Ieturn 'hether the string length is less than the stored int. 3" bool o$erator() (*onst string? str) *onst { return str.length() length; # $rivate4 *onst siUeLt length; #;

'n this code- the constructor accepts a sin&le siUeLt- then stores it as the length data mem#er! 8rom that point forward- whenever the functor is invoked on a particular strin&- the functor's o$erator() function can compare the len&th of that strin& a&ainst length data mem#er! This is e)actly what we want ( a unary function that knows what value to compare the parameter's len&th a&ainst! To tie everythin& to&etherhere's the code we'd use to count the num#er of strin&s in the ve*tor that are shorter than the specified value=
6horter;han st(length); *ountLif(m%Je*tor.begin(), m%Je*tor.end(), st);

8unctors are incredi#le when com#ined with ST al&orithms for this very reason ( they look and act like re&ular functions- #ut have access to e)tra information! This is *ust our first taste of functors- as we continue our e)ploration of C++ you will reco&nize e)actly how much they will influence your pro&ram desi&n! ook #ack to the a#ove code with *ountLif! 'f you'll notice- we created a new 6horter;han o#*ect- then fed it to *ountLif! ,fter the call to *ountLif- odds are we'll never use that particular 6horter;han o#*ect a&ain! This is an e)cellent spot to use temporary o#*ects- since we need a new 6horter;han for the function call #ut don't plan on usin& it afterwards! Thus- we can convert this code=
6horter;han st(length) *ountLif(m%Je*tor.begin(), m%Je*tor.end(), st);

'nto this code=


*ountLif(m%Je*tor.begin(), m%Je*tor.end(), 6horter;han(length));

/ere- 6horter;han(length) constructs a temporary 6horter;han functor with parameter length- then passes it to the *ountLif al&orithm! 2on't &et tripped up #y the synta) ( 6horter;han(length) does not call the 6horter;han's o$erator () function! 'nstead- it invokes the 6horter;han constructor with

1 @<; 1

Chapter /3& Functors

the parameter length to create a temporary o#*ect! Jven if we had written the o$erator() function to take in an int- C++ would realize that the parentheses here means 4construct an o#*ect6 instead of 4invoke o$erator()6 from conte)t! 1riting 2unctor&Com+atible Code 'n previous chapters- you've seen how to write code that accepts a function pointer as a parameter! 8or e)ample- the followin& code accepts a function that takes and returns a double- then prints a ta#le of some values of that function=
*onst *onst *onst *onst double double int double B7o'erPound B@$$erPound BKum6te$s B6te$6iUe = = = = 0.0; 8.0; EH; (B@$$erPound Q B7o'erPound) " BKum6te$s;

void ;abulate&un*tionJalues(double fun*tion(double)) { for(double i = B7o'erPound; i = B@$$erPound; i != B6te$6iUe) *out /f(/ i /) = / fun*tion(i) endl; #

8or any function acceptin& and returnin& a double- we can call ;abulate&un*tionJalues with that function as an ar&ument! 7ut what a#out functors> Can we pass them to ;abulate&un*tionJalues as well> ,s an e)ample- consider the followin& implementation of a Ie*i$ro*al functor- whose o$erator() takes in a double and returns the reciprocal of that double=
*lass Ie*i$ro*al { $ubli*4 double o$erator() (double val) *onst { return 8.0 " val; # #;

3iven this class implementation- is the followin& code le&al>


;abulate&un*tionJalues(Ie*i$ro*al());

KFecall that Ie*i$ro*al() constructs a temporary Ie*i$ro*al o#*ect for use as the parameter to ;abulate&un*tionJalues!L ,t a hi&h level- this code seems perfectly fine! ,fter all- Ie*i$ro*al o#*ects can #e called as thou&h they were unary functions takin& and returnin& doubles- so it seems perfectly reasona#le to pass a Ie*i$ro*al into ;abulate&un*tionJalues. 7ut despite the similarities- Ie*i$ro*al is not a function ( it's a functor ( and so the a#ove code will not compile! The pro#lem is that C++'s static type system prevents function pointers from pointin& to functors- even if the functor has the same parameter and return type as the function pointer! This is not without reason ( the machine code for callin& a function is very different from machine code for callin& a functor- and if C++ were to conflate the two it would result either in slower function calls or undefined runtime #ehavior! 3iven that this code doesn't compile- how can we fi) it> et's #e&in with some o#servations- then &eneralize to the optimal solution! The a#ove code does not compile #ecause we're tryin& to provide a Ie*i$ro*al o#*ect to a function e)pectin& a function pointer! This su&&ests one option ( could we rewrite the ;abulate&un*tionJalues function such that it accepts a Ie*i$ro*al as a parameter instead of a function pointer> 8or e)ample- we could write the followin&=

Chapter /3& Functors


void ;abulate&un*tionJalues(Beciprocal function) { for(double i = B7o'erPound; i = B@$$erPound; i != B6te$6iUe) *out /f(/ i /) = / fun*tion(i) endl; #

1 @<@ 1

"ow- if we call the function as


;abulate&un*tionJalues(Ie*i$ro*al());

The

code is perfectly le&al #ecause the ar&ument has type Ie*i$ro*al and the ;abulate&un*tionJalues function is specifically written to take in o#*ects of type Ie*i$ro*al! 7ut what if we have another functor we want to use in ;abulate&un*tionJalues> 8or e)ample- we mi&ht write a functor called Ar**os that computes the inverse cosine of its parameter- as seen here=
*lass Ar**os { $ubli*4 double o$erator() (double val) *onst { return a*os(val); "" @sing the a*os fun*tion from # #;

*math)

Unfortunately- if we try to call ;abulate&un*tionJalues passin& in an Ar**os o#*ect- as shown here=


;abulate&un*tionJalues(Ar**os());

we'll &et yet another compile1time error- this time #ecause the ;abulate&un*tionJalues function is hardcoded to accept a Ie*i$ro*al- #ut we've tried to provide it an o#*ect of type Ar**os! ,&ain- if we rewrite ;abulate&un*tionJalues to only accept o#*ects of type Ar**os- we could alleviate this pro#lem! Gf course- in doin& so- we would #reak all code that accepted o#*ects of type Ie*i$ro*al! /ow can we resolve this pro#lem> 8ortunately- the answer is yes- thanks to a particularly in&enious trick! 7elow are three versions of ;abulate&un*tionJalues- each of which take in a parameter of a different type=
void ;abulate&un*tionJalues(double fun*tion(double)) { for(double i = B7o'erPound; i = B@$$erPound; i != B6te$6iUe) *out /f(/ i /) = / fun*tion(i) endl;

void ;abulate&un*tionJalues(Ie*i$ro*al fun*tion) { for(double i = B7o'erPound; i = B@$$erPound; i != B6te$6iUe) *out /f(/ i /) = / fun*tion(i) endl;

void ;abulate&un*tionJalues(Ar**os fun*tion) { for(double i = B7o'erPound; i = B@$$erPound; i != B6te$6iUe) *out /f(/ i /) = / fun*tion(i) endl;

# "otice that the only difference #etween the three implementations of ;abulate&un*tionJalues is the type of the parameter to the function! The rest of the code is identical! This su&&ests a rather ele&ant solution usin& templates! 'nstead of providin& multiple different versions of ;abulate&un*tionJalueseach specialized for a particular type of function or functors- we'll write a sin&le template version of ;abulate&un*tionJalues parameterized over the type of the ar&ument! This is shown here=

1 @<A 1

Chapter /3& Functors

tem$late t%$ename @nar%&un*tion) void ;abulate&un*tionJalues(@nar%&un*tion fun*tion) { for(double i = B7o'erPound; i = B@$$erPound; i != B6te$6iUe) *out /f(/ i /) = / fun*tion(i) endl; #

"ow- we can pass any type of o#*ect to ;abulate&un*tionJalues that we want- provided that the ar&ument can #e called with a sin&le double as a parameter to produce a value! This means that we can pass in raw functions- Ie*i$ro*al o#*ects- Ar**os o#*ects- and any other functor classes that happen to mimic functions from doubles to doubles! This hearkens #ack to our discussion of concepts in the previous chapter! 7y writin& ;abulate&un*tionJalues as a template function parameterized over an ar#itrary type- we let clients provide o#*ects of whatever type they see fit- as lon& as it can #e called as a function takin& a double and returnin& a double! 0hen writin& functions that re5uire a user1specified call#ack- you may want to consider parameterizin& the function over the type of the call#ack instead of usin& function pointers! The resultin& code will #e more fle)i#le and future &enerations of pro&rammers will #e much the #etter for your e)tra effort! 6T= Algorit.ms 4e;isited "ow that you're armed with the full power of C++ functors- let's revisit some of the ST al&orithms we've covered and discuss how to ma)imize their firepower! The very first al&orithm we covered was a**umulate- defined in the numeri*) header! 'f you'll recalla**umulate sums up the elements in a ran&e and returns the result! 8or e)ample- &iven a ve*tor int)the followin& code returns the sum of all of the ve*tor's elements=
a**umulate(m%Je*tor.begin(), m%Je*tor.end(), 0);

The first two parameters should #e self1e)planatory- and the third parameter KzeroL represents the initial value of the sum! /owever- this view of a**umulate is limited- and to treat a**umulate as simply a way to sum container elements would #e an error! Father- accumulate is a general"purpose $unction $or trans$orming a collection o$ elements into a single value There is a second version of the a**umulate al&orithm that takes a #inary function as a fourth parameter! This version of a**umulate is implemented like this=
tem$late t%$ename (n$ut(terator, t%$ename ;%$e, t%$ename Pinar%&n) inline ;%$e a**umulate((n$ut(terator start, (n$ut(terator sto$, ;%$e a**umulator, Pinar%&n fn) { 'hile(start 1= sto$) { a**umulator = fn(a**umulator, 3start); !!start; # return initial; #

This a**umulate iterates over the elements of a container- callin& the #inary function on the accumulator and the current element of the container and storin& the result #ack in the accumulator! 'n other wordsa**umulate continuously updates the value of the accumulator #ased on its initial value and the values

Chapter /3& Functors

1 @<? 1

contained in the input ran&e! 8inally- a**umulate returns the accumulator! "ote that the version of a**umulate we encountered earlier is actually a special case of the a#ove version where the provided call#ack function computes the sum of its parameters! To see a**umulate in action- let's consider an e)ample! Fecall that the ST al&orithm lo'erLbound returns an iterator to the first element in a ran&e that compares &reater than or e5ual to some value! /owever- lo'erLbound re5uires the elements in the iterator ran&e to #e in sorted order- so if you have an unsorted ve*tor- you cannot use lo'erLbound! et's write a function @nsorted7o'erPound that accepts a ran&e of iterators and a lower #ound- then returns the value of the least element in the ran&e &reater than or e5ual to the lower #ound! 8or simplicity- let's assume we're workin& with a ve*tor int) so that we don't &et #o&&ed down in template synta)- thou&h this approach can easily #e &eneralized! ,lthou&h this function can #e implemented usin& loops- we can levera&e off of a**umulate to come up with a considera#ly more concise solution! Thus- we'll define a functor class to pass to a**umulate- then write @nsorted7o'erPound as a wrapper call to a**umulate with the proper parameters! Consider the followin& functor=
*lass 7o'erPound0el$er { $ubli*4 e+$li*it 7o'erPound0el$er(int lo'er) 4 lo'estJalue(lo'er) {# int o$erator() (int best6o&ar, int *urrent) { return *urrent )= lo'estJalue ?? *urrent best6o&arT *urrent 4 best6o&ar; # $rivate4 *onst int lo'estJalue; #;

This functor's constructor accepts the value that we want to lower1#ound! 'ts o$erator () function accepts two ints- the first representin& the lowest known value &reater than lo'estJalue and the second the current value! 'f the value of the current element is &reater than or e5ual to the lower #ound and also less than the #est value so far- o$erator () returns the value of the current element! Gtherwiseit simply returns the #est value we've found so far! Thus if we call this functor on every element in the ve*tor and keep track of the return value- we should end up with the lowest value in the ve*tor &reater than or e5ual to the lower #ound! 0e can now write the @nsorted7o'erPound function like this=
int @nsorted7o'erPound(*onst ve*tor int)? in$ut, int lo'erPound) { return a**umulate(in$ut.begin(), in$ut.end(), numeri*Llimits int)44ma+(), 7o'erPound0el$er(lo'erPound)); #

Gur entire function is simply a wrapped call to a**umulate- passin& a specially1constructed 7o'erPound0el$er o#*ect as a parameter! "ote that we've used the value numeri*Llimits int)44ma+() as the initial val#e *or the acc#m#lator. numeri*Llimits- defined in the limits) header- is a traits class that e)ports useful information a#out the #ounds and #ehavior of numeric types- and its ma+ static mem#er function returns the ma)imum possi#le value for an element of the specified type! 0e use this value as the initial value for the accumulator since any inte&er is less than it- so if the ran&e contains no elements &reater than the lower #ound we will &et numeri*Llimits int)44ma+() #ack as a sentinel! 'f you need to transform a ran&e of values into a sin&le result Kof any type you wishL- use a**umulate! To transform a ran&e of values into another ran&e of values- use transform! 0e discussed transform #riefly

1 @<6 1

Chapter /3& Functors

in the chapter on ST al&orithms in the conte)t of 5onvert;o@$$er5ase and 5onvert;o7o'er5ase- #ut such e)amples are *ust the tip of the ice#er&! transform is nothin& short of a miracle function- and it arises a whole host of circumstances!P 3ig.er&$rder !rogramming This discussion of functors was initially motivated #y countin& the num#er of short strings inside of an ST ve*tor! 0e demonstrated that #y usin& *ountLif with a custom functor as the final parameter- we were a#le to write code that counted the num#er of elements in a ve*tor string) whose len&th was less than a certain value! 7ut while this code solved the pro#lem efficiently- we ended up writin& so much code that any potential #enefits of the ST al&orithms were dwarfed #y the time spent writin& the functor! 8or reference- here was the code we used=
*lass 6horter;han { $ubli*4 e+$li*it 6horter;han(siUeLt ma+7ength) 4 length(ma+7ength) {# bool o$erator() (*onst string? str) *onst { return str.length() length; # $rivate4 siUeLt length; #; *onst siUeLt m%Jalue = Get(nteger(); *ountLif(m%Je*tor.begin(), m%Je*tor.end(), 6horter;han(m%Jalue));

Consider the followin& code which also solves the pro#lem- #ut #y usin& a simple for loop=
*onst int m%Jalue = Get(nteger(); int total = 0; for(int i = 0; i m%Je*tor.siUe(); !!i) if(m%Je*tor[i].length() m%Jalue) !!total;

This code is considera#ly more reada#le than the functor version and is appro)imately a third as lon&! 7y almost any metric- this code is superior to the earlier version! 'f you'll recall- we were motivated to write this 6horter;han functor #ecause we were una#le to use *ountLif in con*unction with a traditional C++ function! 7ecause *ountLif accepts as a parameter a unary function- we could not write a C++ function that could accept #oth the current container element and the value to compare its len&th a&ainst! /owever- we did note that were *ountLif to accept a #inary function and e)tra client data- then we could have written a simple C++ function like this one=
bool 7ength(s7ess;han(*onst string? str, int threshold) { return str.length() threshold; #

,nd then passed it in- alon& with the cutoff len&th- to the *ountLif function! The fundamental pro#lem is that the ST *ountLif al&orithm re5uires a sin&le1parameter function- #ut the function we want to use re5uires two pieces of data! 0e want the ST al&orithms to use our two1parameter function 7ength(s7ess;han- #ut with the second parameter always havin& the same
P Those of you familiar with functional pro&rammin& mi&ht reco&nize hi&her1order functions Bap and Feduce!
a**umulate

and

transform

as the classic

Chapter /3& Functors

1 @<D 1

value! 0hat if somehow we could modify 7ength(s7ess;han #y 4lockin& in6 the second parameter> 'n other words- we'd like to take a function that looks like this=
bool JengthIsJess%han string str

(parameter)
int length

(parameter)

,nd transform it into another function that looks like this=


Uodified JengthIsJess%han string str

(parameter)
int length

"ow- if we call this special version of 7ength(s7ess;han with a sin&le parameter Kcall it strL- it would #e as thou&h we had called the initial version of 7ength(s7ess;han- passin& as parameters the value of str and the stored value ?! This then returns whether the len&th of the str strin& is less than ?! Jssentially#y #indin& the second parameter of the two1parameter 7ength(s7ess;han function- we end up with a one1parameter function that descri#es e)actly the predicate function we want to provide to *ountLif! Thus- at a hi&h level- the code we want to #e a#le to write should look like this=
*ountLif(v.begin(), v.end(), the $unction $ormed by loc*ing ? as the second parameter o$ 4ength5s4ess6han 7

This sort of pro&rammin&- where functions can #e created and modified *ust like re&ular o#*ects- is known as higher"order programming! 0hile #y default C++ does not support hi&her1order pro&rammin&- usin& functors and the ST functional pro&rammin& li#raries- in many cases it is possi#le to write hi&her1order code in C++! 'n the remainder of this chapter- we'll e)plore the ST functional pro&rammin& li#raries and see how to use hi&her1order pro&rammin& to superchar&e ST al&orithms! Ada+table 2unctions To provide hi&her1order pro&rammin& support- standard C++ provides the fun*tional) li#rary! fun*tional) e)ports several useful functions that can transform and modify functions on1the1fly to yield new functions more suita#le to the task at hand! /owever- #ecause of several lan&ua&e limitationsthe fun*tional) li#rary can only modify specially constructed functions called 4adapta#le functions-6 functors Knot re&ular C++ functionsL that e)port information a#out their parameter and return types! 8ortunately- any one1 or two1parameter function can easily #e converted into an e5uivalent adapta#le function! 8or e)ample- suppose you want to make an adapta#le function called :%&un*tion that takes a string #y reference1to1*onst as a parameter and returns a bool- as shown #elow=

1 @<E 1
*lass :%&un*tion { $ubli*4 bool o$erator() (*onst string? str) *onst { "3 &un*tion that mani$ulates a string 3" # #;

Chapter /3& Functors

"ow- to make this function an adapta#le function- we need to specify some additional information a#out the parameter and return types of this functor's o$erator () function! To assist in this process- the functional li#rary defines a helper template class called unar%Lfun*tion- which is prototyped #elow=
tem$late t%$ename <arameter;%$e, t%$ename Ieturn;%$e) *lass unar%Lfun*tion;

The first template ar&ument represents the type of the parameter to the functionQ the second- the function's return type! Unlike the other classes you have seen #efore- the unar%Lfun*tion class contains no data mem#ers and no mem#er functions! 'nstead- it performs some #ehind1the1scenes ma&ic with the t%$edef keyword to e)port the information e)pressed in the template types to the rest of the functional pro&rammin& li#rary! Since we want our a#ove functor to also e)port this information- we'll inheritance to import all of the information from unar%Lfun*tion into our :%&un*tion functor! 7ecause :%&un*tion accepts as a parameter an o#*ect of type string and returns a varia#le of type bool- we will have :%&un*tion inherit from the type unar%Lfun*tion string, bool)! The synta) to accomplish this is shown #elow=
*lass :%&un*tion 4 $ubli* unar%Lfun*tion string, bool) { $ubli*4 bool o$erator() (*onst string? str) *onst { "3 &un*tion that mani$ulates a string 3" # #;

0e'll e)plore inheritance in more detail later- #ut for now *ust think of it as a way for importin& information from class into another! "ote that althou&h the function accepts as its parameter a *onst string?- we chose to use a unar%Lfun*tion specialized for the type string! The reason is somewhat technical and has to do with how unar%Lfun*tion interacts with other functional li#rary components- so for now *ust remem#er that you should not specify reference1to1 *onst types inside the unar%Lfun*tion template parametrization! The synta) for convertin& a #inary functor into an adapta#le #inary function works similarly to the a#ove code for unary functions! Suppose that we'd like to make an adapta#le #inary function that accepts a string and an int and returns a bool! 0e #e&in #y writin& the #asic functor code- as shown here=
*lass :%=ther&un*tion { $ubli*4 bool o$erator() (*onst string? str, int val) *onst { "3 9o something, return a bool. 3" # #;

To convert this functor into an adapta#le function- we'll have it inherit from binar%Lfun*tion! unar%Lfun*tion- binar%Lfun*tion is a template class that's defined as

ike

Chapter /3& Functors


tem$late t%$ename <aram8;%$e, t%$ename <aramE;%$e, t%$ename Iesult;%$e) *lass binar%Lfun*tion;

1 @<< 1

Thus the adapta#le version of :%=ther&un*tion would #e


*lass :%=ther&un*tion" $ubli* binar%Lfun*tion string, int, bool) { $ubli*4 bool o$erator() (*onst string? str, int val) *onst { "3 9o something, return a bool. 3" # #;

0hile the a#ove approach for &eneratin& adapta#le functions is perfectly le&al- it's a #it clunky and we still have a hi&h ratio of #oilerplate code to actual lo&ic! 8ortunately- the ST functional li#rary provides the powerful #ut cryptically named $trLfun3 function that transforms a re&ular C++ function into an adapta#le function! $trLfun can convert #oth unary and #inary C++ functions into adapta#le functions with the correct parameter types- meanin& that you can skip the hassle of the a#ove code #y simply writin& normal functions and then usin& $trLfun to transform them into adapta#le functions! 8or e)ample- &iven the followin& C++ function=
bool 7ength(s7ess;han(string m%6tr, int threshold) { return m%6tr.length() threshold; #

'f we need to &et an adapta#le version of that function- we can write $trLfun(7ength(s7ess;han) in the spot where the adapta#le function is needed!
$trLfun is a useful #ut imperfect tool! Bost nota#ly- you cannot use $trLfun on functions that accept parameters as reference1to1*onst! $trLfun returns a unar%Lfun*tion o#*ect- and as mentioned a#oveyou cannot specify reference1to1*onst as template ar&uments to unar%Lfun*tion! ,lso- #ecause of the way that the C++ compiler &enerates code for functors- code that uses $trLfun can #e a #it slower than

code usin& functors! 8or situations where you'd like to convert a mem#er function into an adapta#le function- you can use the memLfun or memLfunLref functions! These functions convert mem#er functions into unary functions that accept as input a receiver o#*ect- then invoke that mem#er function on the receiver! The difference #etween memLfun and memLfunLref is how they accept their parameters ( memLfun accepts a pointer to the receiver o#*ect- while memLfunLref accepts a re$erence to the receiver! 8or e)ample- &iven a ve*tor string)- the followin& code will print out the len&ths of all of the strin&s in the ve*tor=
transform(m%Je*tor.begin(), m%Je*tor.end(), ostreamLiterator int)(*out, /,n/), memLfunLref(?string44length));

Bet.s dissect this call to transform, since there.s a lot /oin/ on. The *irst two parameters delineate the inp#t ran/e, in this case the *#ll contents o* m%Je*tor. The third parameter speci*ies where to p#t the o#tp#t, and since here it.s an ostreamLiterator the o#tp#t will be printed directly to the console instead o* stored in some other location. The *inal parameter is memLfunLref(?string44length), a *#nction that accepts as inp#t a string and then ret#rns the val#e o* the length member *#nction called on that string.
memLfunLref can also #e used to convert unary Kone1parameterL mem#er functions into adapta#le #inary

functions that take as a first parameter the o#*ect to apply the function to and as a second parameter the
P $trLfun is short for 4pointer function6- not 4fun with pointers!6

1 A00 1

Chapter /3& Functors

parameter to the function! 0hen we cover #inders in the ne)t section- you should &et a #etter feel for e)actly how useful this is! Binding !arameters "ow that we've covered how the ST functional li#rary handles adapta#le functions- let's consider how we can use them in practice! ,t the #e&innin& of this chapter- we introduced the notion of parameter binding- convertin& a two1 parameter function into a one1parameter function #y lockin& in the value of one of its parameters! To allow you to #ind parameters to functions- the ST functional pro&rammin& li#rary e)ports two functions'ind1st and 'ind2nd- which accept as parameters an adapta#le function and a value to #ind and return new functions that are e5ual to the old functions with the specified values #ound in place! 8or e)ample&iven the followin& implementation of 7ength(s7ess;han=
bool 7ength(s7ess;han(string str, int threshold) { return str.length() threshold; #

0e could use the followin& synta) to construct a function that's 7ength(s7ess;han with the value five #ound to the second parameter=
bindEnd($trLfun(7ength(s7ess;han), H)

The line bindEnd($trLfun(7ength(s7ess;han), H) first uses $trLfun to &enerate an adapta#le version of the 7ength(s7ess;han function- then uses bindEnd to lock the parameter ? in place! The result is a new unary function that accepts a string parameter and returns if that strin&'s len&th is less than ?- the value we #ound to the second parameter! Since bindEnd is a function that accepts a function as a parameter and returns a function as a result- bindEnd is a function that is sometimes referred to as a higher"order $unction! 7ecause the result of the a#ove call to bindEnd is a unary function that determines if a strin& has len&th less than five- we can use the *ountLif al&orithm to count the num#er of values less than five #y usin& the followin& code=
*ountLif(*ontainer.begin(), *ontainer.end(), bindEnd($trLfun(7ength(s7ess;han), H));

Compare this code to the functor1#ased approach illustrated at the start of this chapter! This version of the code is much- much shorter than the previous version! 'f you aren't #e&innin& to appreciate e)actly how much power and fle)i#ility the fun*tional) li#rary provides- skip ahead and take a look at the practice pro#lems! The bind8st function acts similarly to bindEnd- e)cept that Kas its name su&&estsL it #inds the first parameter of a function! Feturnin& to the a#ove e)ample- &iven a ve*tor int)- we could count the num#er of elements in that ve*tor smaller than the len&th of strin& 4C++R6 #y writin&
*ountLif(m%Je*tor.begin(), m%Je*tor.end(), bind8st($trLfun(7ength(s7ess;han), /5!!1/));

K,dmittedly- this isn't the most practical use case for bind8st- #ut it does &et the point acrossL!

Chapter /3& Functors

1 A01 1

'n the ST functional pro&rammin& li#rary- parameter #indin& is restricted only to #inary functions! Thus you cannot #ind a parameter in a three1parameter function to yield a new #inary function- nor can you #ind the parameter of a unary function to yield a zero1parameter K4nullary6L function! 8or these operations- you'll need to create your own custom functors- as shown in the practice pro#lems at the end of this chapter! @egating 4esults Suppose that &iven a function 7ength(s7ess;han- we want to find the num#er of strin&s in a container that are not less than a certain len&th! 0hile we could simply write another function 7ength(sKot7ess;han- it would #e much more convenient if we could somehow tell C++ to take whatever value 7ength(s7ess;han returns and to use the opposite result! That is- &iven a function that looks like this=

YES
Input

JengthIsJess%han

NO
0e'd like to chan&e it into a function that looks like this=

NO
Input

JengthIsJess%han in3+rt+r

YES

This operation is negation ( constructin& a new function whose return value has the opposite value of the input function! There are two ST ne&ator functions ( not8 and notE ( that return the ne&ated result of a unary or #inary predicate function- respectively! Thus- the a#ove function that's a ne&ation of 7ength(s7ess;han could #e written as notE($trLfun(7ength(s7ess;han))! Since notE returns an adapta#le function- we can then pass the result of this function to bindEnd to &enerate a unary function that returns whether a strin&'s len&th is at least a certain threshold value! 8or e)ample- here's code that returns the num#er of strings in a container with len&th at least ?=
*ountLif(*ontainer.begin(), *ontainer.end(), bindEnd(notE($trLfun(7ength(s7ess;han)), H));

1 A0; 1

Chapter /3& Functors

0hile this line is dense- it ele&antly solves the pro#lem at hand #y com#inin& and modifyin& e)istin& code to create entirely different functions! Such is the #eauty and simplicity of hi&her1order pro&rammin& ( why rewrite code from scratch when you already have all the pieces individually assem#led>

Chapter /3& Functors $+erator 2unctions

1 A0@ 1

et's suppose that you have a container of ints and you'd like to add 1@D to each of them! Fecall that you can use the ST transform al&orithm to apply a function to each element in a container and then store the result! 7ecause we're addin& 1@D to each element- we mi&ht consider writin& a function like this one=
int Add8CD(int $aram) { return $aram ! 8CD; #

,nd then writin&


transform(*ontainer.begin(), *ontainer.end(), *ontainer.begin(), Add8CD);

0hile this code works correctly- this approach is not particularly ro#ust! 0hat if later on we needed to increment all elements in a container #y A;- or perhaps #y an ar#itrary value> Thus- we mi&ht want to consider replacin& Add8CD #y a function like this one=
int Add;'o(nts(int one, int t'o) { return one ! t'o; #

,nd then usin& #inders to lock the second parameter in place! 8or e)ample- here's code that's e5uivalent to what we've written a#ove=
transform(*ontainer.begin(), *ontainer.end(), *ontainer.begin(), bindEnd($trLfun(Add;'o(nts), 8CD));

,t this point- our code is correct- #ut it can &et a #it annoyin& to have to write a function Add;'o(nts that simply adds two inte&ers! Boreover- if we then need code to increment all doubles in a container #y 1!@Dwe would need to write another function Add;'o9oubles to avoid pro#lems from typecasts and truncations! 8ortunately- the desi&ners of the ST functional li#rary reco&nized how tedious it is to write out this sort of code- and so the ST functional li#rary provides a lar&e num#er of template adapta#le function classes that simply apply the #asic C++ operators to two values! 8or e)ample- in the a#ove codewe can use the adapta#le function class plus&int( instead of our Add;'o(nts function- resultin& in code that looks like this=
transform(*ontainer.begin(), *ontainer.end(), *ontainer.begin(), bindEnd($lus int)(), 8CD));

"ote that we need to write $lus int)() instead of simply $lus int)- since we're usin& the temporary o#*ect synta) to construct a $lus int) o#*ect for bindEnd! 8or&ettin& the parentheses can cause a ma*or compiler error headache that can take a while to track down! ,lso notice that we don't need to use $trLfun here- since $lus int) is already an adapta#le function! 8or reference- here's a list of the 4operator functions6 e)ported #y fun*tional)=
$lus e[ualLto logi*alLand minus notLe[ualLto logi*alLor multi$lies greater logi*alLnot divides less modulus negate

greaterLe[ual lessLe[ual

To see an e)ample that com#ines the techni5ues from the previous few sections- let's consider a function that accepts a ve*tor double) and converts each element in the ve*tor to its reciprocal Kone divided #y

1 A0A 1

Chapter /3& Functors

the valueL! 7ecause we want to convert each element with value 4 to the value 1H4- we can use a com#ination of #inders and operator functions to solve this pro#lem #y #indin& the value 1!0 to the first parameter of the divides double) functor! The result is a unary function that accepts a parameter of type double and returns the element's reciprocal! The resultin& code looks like this=
transform(v.begin(), v.end(), v.begin(), bind8st(divides double)(), 8.0));

This code is concise and ele&ant- solvin& the pro#lem in a small space and makin& e)plicit what operations are #ein& performed on the data! Gnif/ing 2unctions and 2unctors There are a hu&e num#er of ways to define a function or function1like o#*ect in C++- each of which has sli&htly different synta) and #ehavior! 8or e)ample- suppose that we want to write a function that accepts as input a function that can accept an int and return a double! 0hile of course we could accept a double (3) (int) ( a pointer to a function acceptin& an int and returnin& a double ( this is overly restrictive! 8or e)ample- all of the followin& functions can #e used as thou&h they were functions takin& in an int and returnin& a double=
double &n8(*onst int?); int &nE(int); int &nC(*onst int?); "3 A**e$t b% referen*e-to-*onst, %ield double. 3" "3 A**e$t $arameter as a int, return int. 3" "3 A**e$t referen*e-to-*onst int, return int. 3"

'n addition- if we *ust accept a double (3) (int)- we also can't accept functors as input- meanin& that neither of these o#*ects #elow ( #oth of which can accept an int and return a double ( could #e used=
"3 &un*tor a**e$ting an int and returning a double. 3" *lass :%&un*tor { $ubli*4 double o$erator() (int); #; "3 Ada$table fun*tion a**e$ting double and returning a double. 3" bindEnd(multi$lies int)(), 8CD);

Jarlier in this chapter- we saw how we can write functions that accept any of the a#ove functions usin& templates- as shown here=
tem$late t%$ename @nar%&un*tion) void 9o6omething(@nar%&un*tion fn) { "3 ... 3" #

'f we want to write a $unction that accepts a function as input we can rely on templates- #ut what if we want to write a class that needs to store a function of any ar#itrary type> To &ive a concrete e)amplesuppose that we're desi&nin& a class representin& a &raphical window and we want the client to #e a#le to control the window's size and position! The window o#*ect- which we'll assume is of type 2indo'- thus allows the user to provide a function that will #e invoked whenever the window is a#out to chan&e size! The user's function then takes in an int representin& the potential new width of the window and returns an int representin& what the user wants the new window size to #e! 8or e)ample- if we want to create a window that can't #e more than 100 pi)els wide- we could pass in this function=
int 5lam$;o800<i+els(int siUe) { return min(siUe, 800); #

Chapter /3& Functors ,lternatively- if we want the window size to always #e 100 pi)els- we could pass in this function=
int Al'a%s800<i+els(int) { return 800; "" (gnore $arameter #

1 A0? 1

3iven that we need to store a function of an ar#itrary type inside the 2indo' class- how mi&ht we desi&n 2indo'> Usin& the approach outlined a#ove- we could parameterize the 2indo' class over the type of the function it stores- as shown here=
tem$late t%$ename 2idth&un*tion) *lass 2indo' { $ubli*4 2indo'(2idth&un*tion fn, "3 ... 3"); "3 ... 3" $rivate4 2idth&un*tion 'idth; #; "3 ... 3"

3iven this implementation of 2indo'- we could then specify that a window should #e no more than 100 pi)els wide #y writin&
2indo' int (3)(int)) m%2indo'(5lam$;o800<i+els);

This 0indow class lets us use any reasona#le function to determine the window size- #ut has several serious draw#acks! 8irst- it re5uires the 2indo' client to e)plicitly parameterize 0indow over the type of call#ack #ein& stored! 0hen workin& with function pointers this results in lon& and convoluted varia#le declarations Klook a#ove for an e)ampleL- and when workin& with li#rary functors such as those in the ST fun*tional) li#rary Ke!&! bindEnd ($trLfun(:%&un*tion), 8CD)LP- we could end up with a 2indo' of such a complicated type that it would #e infeasi#le to use with without the aid of t%$edef! 7ut a more serious pro#lem is that this approach causes two 2indo's that don't use the same type of function to compute width to have completely different types! That is- a 2indo' usin& a raw C++ function to compute its size would have a different type from a 2indo' that computed its size with a functor! Conse5uently- we couldn't make a ve*tor 2indo')- #ut instead would have to make a ve*tor 2indo' int (3)(int)) ) or a ve*tor 2indo' :%&un*tor;%$e) )! Similarly- if we want to write a function that accepts a 2indo'we can't *ust write the followin&=
void 9o6omething(*onst 2indo'? ') { "" Error Q 2indo' is a tem$late, not a t%$e "3 ... 3" #

0e instead would have to write


tem$late t%$ename 2indo';%$e) void 9o6omething(*onst 2indo';%$e? ') { "" 7egal but a'B'ard "3 ... 3" # P ,s an 8.'- the type of bindEnd($trLfun(:%&un*tion),
8CD) is

binderEnd $ointerLtoLbinar%Lfun*tion Arg8, ArgE, Iet) )

where Arg8- ArgE- and Iet are the ar&ument and return types of the :%&un*tion function!

1 A06 1

Chapter /3& Functors

't should #e clear that templatizin& the 2indo' class over the type of the call#ack function does not work well! /ow can we resolve this pro#lem> 'n the remainder of this chapter- see a #eautiful solution to this pro#lem that will unify our treatment of functors- inheritance- templates- operator overloadin&- copy functions- and conversion constructors! The result is amazin&ly ele&ant and hopefully will impress upon you e)actly how powerful functors are as a techni5ue! In.eritance to t.e 4escue et's take a few minutes to think a#out the pro#lem we're facin&! 0e have a collection of different o#*ects that each have similar functionality Kthey can #e called as functionsL- #ut we don't know e)actly which o#*ect the user will provide! This sounds e)actly like the sort of pro#lem we can solve usin& inheritance and virtual functions! 7ut we have a pro#lem ( inheritance only applies to ob!ects- #ut some of the values we mi&ht want to store are simple function pointers- which are primitives! 8ortunately- we can apply a techni5ue called the Fundamental Theorem o$ ,o$tware Engineering Kor 8TSJL to solve this pro#lem= T.eorem (T.e 2undamental T.eorem of 6oftware )ngineering )& ,ny pro#lem can #e solved #y addin& enou&h layers of indirection! This is a very useful pro&rammin& concept that will prove relevant time and time a&ain ( make sure you remem#er itR 'n this particular application- the 8TSJ says that we need to distance ourselves #y one level from raw function pointers and functor classes! This leads to the followin& o#servation= while we mi&ht not #e a#le to treat functors and function pointers polymorphically- we certainly can create a new class hierarchy and then treat that class polymorphically! The idea &oes somethin& like this ( rather than havin& the user provide us a functor or function pointer which could #e of any type- instead we'll define an a#stract class e)portin& the call#ack function- then will have the user provide a su#class which implements the call#ack! Gne possi#le #ase class in this hierarchy is shown #elow=
*lass (nt&un*tion { $ubli*4 "3 <ol%mor$hi* *lasses need virtual destru*tors. 3" virtual c(nt&un*tion() {# "3 e+e*ute() a*tuall% *alls the $ro$er fun*tion and returns the value. 3" virtual int e+e*ute(int value) *onst = 0; #; (nt&un*tion e4ports a sin/le *#nction called e+e*ute which accepts an int and ret#rns an int. This

*#nction is mar0ed p#rely virt#al since it.s #nclear e4actly what this *#nction sho#ld do. +*ter all, we.re tryin/ to store an arbitrary *#nction, so there.s no clearly)de*ined de*a#lt behavior *or e+e*ute. He can now modi*y the implementation o* 2indo' to hold a pointer to an (nt&un*tion instead o* bein/ templati=ed over the type o* the *#nction, as shown hereF
*lass 2indo' { $ubli*4 2indo'((nt&un*tion3 siUe&un*tion, "3 ... 3"); "3 ... 3" $rivate4 (nt&un*tion3 fn; #;

Chapter /3& Functors "ow- if we wanted to clamp the window to 100 pi)els- we can do the followin&=
*lass 5lam$;o800<i+els&un*tion4 $ubli* (nt&un*tion { $ubli*4 virtual int e+e*ute(int siUe) *onst { return min(siUe, 800); # #; 2indo' m%2indo'(ne' 5lam$;o800<i+els&un*tion, "3 ... 3");

1 A0D 1

Similarly- if we want to have a window that's always 100 pi)els wide- we could write
*lass &i+ed6iUe&un*tion4 $ubli* (nt&un*tion { $ubli*4 virtual int e+e*ute(int siUe) *onst { return 800; # #; 2indo' m%2indo'(ne' &i+ed6iUe&un*tion, "3 ... 3");

't seems as thou&h we've solved the pro#lem ( we now have a 2indo' class that allows us to fully customize its resizin& #ehavior ( what more could we possi#ly want> The main pro#lem with our solution is the sheer amount of #oilerplate code clients of 2indo' have to write if they want to chan&e the window's resizin& #ehavior! Gur initial &oal was to let class clients pass raw C++ functions and functors to the 2indo' class- #ut now clients have to su#class (nt&un*tion to &et the *o# done! 7oth of the a#ove su#classes are len&thy even thou&h they only e)port a sin&le function! 's there a simpler way to do this> The answer- of course- is yes! Suppose we have a pure C++ function that accepts an int #y value and returns an int that we want to use for our resizin& function in the 2indo' classQ perhaps it's the 5lam$;o800<i+els function we defined earlier- or perhaps it's Al'a%s800<i+els! Father than definin& a new su#class of (nt&un*tion for every sin&le one of these functions- instead we'll #uild a sin&le class that's desi&ned to wrap up a function pointer in a packa&e that's compati#le with the (nt&un*tion interface! That is- we can define a su#class of (nt&un*tion whose constructor accepts a function pointer and whose e)ecute calls this function! This is the 8undamental Theorem of Software Jn&ineerin& in action ( we couldn't directly treat the raw C++ function polymorphically- #ut #y a#stractin& #y a level we can directly apply inheritance! /ere's one possi#le implementation of the su#class=
*lass A*tual&un*tion4 $ubli* (nt&un*tion { $ubli*4 e+$li*it A*tual&un*tion(int (3fn)(int)) 4 fun*tion(fn) {# virtual int e+e*ute(int value) *onst { return fun*tion(value); # $rivate4 int (3fun*tion)(int); #;

"ow- if we want to use 5lam$;o800<i+els inside of 2indo'- we can write=

1 A0E 1

Chapter /3& Functors

2indo' m%2indo'(ne' A*tual&un*tion(5lam$;o800<i+els), "3 ... 3");

There is a #it of e)tra code for creatin& the A*tual&un*tion o#*ect- #ut this is a one1time cost! 0e can now use A*tual&un*tion to wrap any raw C++ function acceptin& an int and returnin& an int and will save a lot of time typin& out new su#classes of (nt&un*tion for every call#ack! "ow- suppose that we have a functor class- which we'll call :%&un*tor- that we want to use inside the 2indo' class! Then we could define a su#class that looks like this=
*lass :%&un*tor&un*tion4 $ubli* (nt&un*tion { $ubli*4 e+$li*it :%&un*tor&un*tion(:%&un*tor fn) 4 fun*tion(fn) {# virtual int e+e*ute(int value) *onst { return fun*tion(value); # $rivate4 :%&un*tor fun*tion; #;

,nd could then use it like this=


2indo' m%2indo'(ne' :%&un*tor&un*tion(:%&un*tor(8CD)), "3 ... 3");

Hhere we ass#me *or simplicity that the :%&un*tor class has a #nary constr#ctor. 0e're &ettin& much closer to an ideal solution! /an& in thereQ the ne)t step is pretty e)citin&! Tem+lates to t.e 4escue ,t this point we a&ain could *ust call it 5uits ( we've solved the pro#lem we set out to solve and usin& the a#ove pattern our 2indo' class can use any C++ function or functor we want! /owever- we are close to an o#servation that will &reatly simplify the implementation of 2indo' and will yield a much more &eneral solution! et's reprint the two su#classes of (nt&un*tion we *ust defined a#ove which wrap function pointers and functors=

Chapter /3& Functors


*lass A*tual&un*tion4 $ubli* (nt&un*tion { $ubli*4 e+$li*it A*tual&un*tion(int (3fn)(int)) 4 fun*tion(fn) {# virtual int e+e*ute(int value) *onst { return fun*tion(value); # $rivate4 int (3*onst fun*tion)(int); #; *lass :%&un*tor&un*tion4 $ubli* (nt&un*tion { $ubli*4 e+$li*it :%&un*tor&un*tion(:%&un*tor fn) 4 fun*tion(fn) {# virtual int e+e*ute(int value) *onst { return fun*tion(value); # $rivate4 :%&un*tor fun*tion; #;

1 A0< 1

2* yo#.ll notice, besides the name o* the classes, the only di**erence between these two classes is what type o* obAect is bein/ stored. This similarity is no coincidence G any callable *#nction or *#nctor wo#ld reE#ire a s#bclass with e4actly this str#ct#re. <ather than reE#irin/ the client o* 2indo' to reimplement this s#bclass *rom scratch each time, we can instead create a template class that.s a s#bclass o* (nt&un*tion. 2t.s rare in practice to see templates and inheritance mi4ed this way, b#t here it wor0s o#t bea#ti*#lly. Here.s one implementationF
tem$late t%$ename @nar%&un*tion) *lass 6$e*ifi*&un*tion4 $ubli* (nt&un*tion { $ubli*4 e+$li*it 6$e*ifi*&un*tion(@nar%&un*tion fn) 4 fun*tion(fn) {# virtual int e+e*ute(int value) *onst { return fun*tion(value); # $rivate4 @nar%&un*tion fun*tion; #;

He now can #se the 2indo' class as *ollowsF


2indo' m%2indo'(ne' 6$e*ifi*&un*tion int(3)(int))(5lam$;o800<i+els), "3...3"); 2indo' m%2indo'(ne' 6$e*ifi*&un*tion :%&un*tor)(:%&un*tor(8CD)), "3...3");

The synta4 here mi/ht be a bit tric0y, b#t we.ve /reatly red#ced the comple4ity associated with the 2indo' class since clients no lon/er have to implement their own s#bclasses o* (nt&un*tion.

1 A10 1 $ne (ore Abstraction

Chapter /3& Functors

This desi&n process has consisted primarily of addin& more and more a#stractions on top of the system we're desi&nin&- and it's time for one final leap! et's think a#out what we've constructed so far! 0e've #uilt a class hierarchy with a sin&le #ase class and a template for creatin& as many su#classes as we need! /owever- everythin& we've written has #een hardcoded with the assumption that the 2indo' class is the only class that mi&ht want this sort of functionality! /avin& the a#ility to store and call a function of any conceiva#le type is enormously useful- and if we can somehow encapsulate all of the necessary machinery to &et this workin& into a sin&le class- we will #e a#le to reuse what we've *ust #uilt time and time a&ain! 'n this ne)t section- that's e)actly what we'll #e&in doin&! 0e'll #e&in #y movin& the code from 2indo' that mana&es the stored function into a dedicated class called &un*tion! The #asic interface for &un*tion is shown #elow=
*lass &un*tion { $ubli*4 "3 5onstru*tor and destru*tor. &un*tion((nt&un*tion3 fn); c&un*tion();

2eAll im$lement *o$%ing in a bit. 3"

"3 &un*tion is a fun*tor that *alls into the stored resour*e. 3" int o$erator() (int value) *onst; $rivate4 (nt&un*tion3 fun*tion; #;

0e'll leave the &un*tion constructor left as an implicit conversion constructor- since that way we can implicitly convert #etween a calla#le (nt&un*tion pointer and a &un*tion functor! 0e can then implement the a#ove functions as follows=
"3 5onstru*tor a**e$ts an (nt&un*tion and stores it. 3" &un*tion44&un*tion((nt&un*tion3 fn) 4 fun*tion(fn) { "" 0andled in initialiUer list # "3 9estru*tor deallo*ates the stored fun*tion. 3" &un*tion44c&un*tion() { delete fun*tion; # "3 &un*tion *all >ust *alls through to the $ointer and returns the result. 3" int &un*tion44o$erator() (int value) *onst { return fun*tion-)e+e*ute(value); #

"othin& here should #e too out1of1the1ordinary ( after all- this is pretty much the same code that we had inside the 2indo' class! 3iven this version of &un*tion- we can write code that looks like this=

Chapter /3& Functors

1 A11 1

&un*tion m%&un*tion = ne' 6$e*ifi*&un*tion int (3)(int))(5lam$;o800<i+els); *out m%&un*tion(8CD) endl; "" <rints 800 *out m%&un*tion(GE) endl; "" <rints GE

'f you're a #it worried that the synta) ne' 6$e*ifi*&un*tion int (3)(int))(5lam$;o800<i+els) is unnecessarily #ulky- that's a#solutely correct! 2on't worry- in a #it we'll see how to eliminate it! 'n the meantime- however- let's implement the copy #ehavior for the &un*tion class! ,fter all- there's no reason that we shouldn't #e a#le to copy &un*tion o#*ects- and definin& copy #ehavior like this will lead to some very impressive results in a #it! 0e'll #e&in #y definin& the proper functions inside the 8unction class- as seen here=
*lass &un*tion { $ubli*4 "3 5onstru*tor and destru*tor. 3" &un*tion((nt&un*tion3 fn); c&un*tion(); "3 5o$% su$$ort. 3" &un*tion(*onst &un*tion? other); &un*tion? o$erator= (*onst &un*tion? other); "3 &un*tion is a fun*tor that *alls into the stored resour*e. 3" int o$erator() (int value) *onst; $rivate4 (nt&un*tion3 fun*tion; void *lear(); void *o$%=ther(*onst &un*tion? other);

#;

"ow- since the &un*tion class contains only a sin&le data mem#er Kthe (nt&un*tion pointerL- to make a deep1copy of a &un*tion we simply need to make a deep copy of its re5uisite (nt&un*tion! 7ut here we run into a pro#lem! (nt&un*tion is an a#stract class and we can't tell at compile1time what type of o#*ect is actually #ein& pointed at #y the function pointer! /ow- then- can we make a deep1copy of the (nt&un*tion> The answer is surprisin&ly strai&htforward ( we'll *ust introduce a new virtual function to the (nt&un*tion class that returns a deep copy of the receiver o#*ect! Since this function duplicates an e)istin& o#*ect- we'll call it *lone! The interface for (nt&un*tion now looks like this=
*lass (nt&un*tion { $ubli*4 "3 <ol%mor$hi* *lasses should have virtual destru*tors. 3" virtual c(nt&un*tion() { # "3 e+e*ute() a*tuall% *alls the $ro$er fun*tion and returns the value. 3" virtual int e+e*ute(int value) *onst = 0; "3 *lone() returns a dee$-*o$% of the re*eiver ob>e*t. 3" virtual (nt&un*tion3 *lone() *onst = 0; #;

0e can then update the template class 6$e*ifi*&un*tion to implement *lone as follows=

1 A1; 1

Chapter /3& Functors

tem$late t%$ename @nar%&un*tion) *lass 6$e*ifi*&un*tion4 $ubli* (nt&un*tion { $ubli*4 e+$li*it 6$e*ifi*&un*tion(@nar%&un*tion fn) 4 fun*tion(fn) {# virtual int e+e*ute(int value) *onst { return fun*tion(value); # virtual (nt&un*tion3 *lone() *onst { return ne' 6$e*ifi*&un*tion(3this); # $rivate4 @nar%&un*tion fun*tion; #;

/ere- the implementation of *lone returns a new 6$e*ifi*&un*tion initialized via the copy constructor as a copy of the receiver o#*ect! "ote that we haven't e)plicitly defined a copy constructor for 6$e*ifi*&un*tion and are relyin& here on C++'s automatically1&enerated copy function to do the trick for us! This assumes- of course- that the @nar%&un*tion type correctly supports deep1copyin&- #ut this isn't a pro#lem since raw function pointers can trivially #e deep1copied as can all primitive types and it's rare to find functor classes with no copy support! 0e can then implement the copy constructor- assi&nment operator- destructor- and helper functions for 8unction as follows=
&un*tion44c&un*tion() { *lear(); # &un*tion44&un*tion(*onst &un*tion? other) { *o$%=ther(other); # &un*tion? &un*tion44o$erator= (*onst &un*tion? other) { if(this 1= ?other) { *lear(); *o$%=ther(other); # return 3this; # void &un*tion44*lear() { delete fun*tion; # void &un*tion44*o$%=ther(*onst &un*tion? other) { "3 0ave the stored fun*tion tell us ho' to *o$% itself. 3" fun*tion = other.fun*tion-)*lone(); #

Gur &un*tion class is now startin& to take shapeR 3iding Ipecific?unction Fi&ht now our &un*tion class has full deep1copy support and usin& 6$e*ifi*&un*tion ;) can store any type of calla#le function! /owever- clients of &un*tion have to e)plicitly wrap any function they want to

Chapter /3& Functors

1 A1@ 1

store inside &un*tion in the 6$e*ifi*&un*tion class! This has several pro#lems! 8irst and foremostthis #reaks encapsulation! 6$e*ifi*&un*tion is only used internally to the &un*tion class- never e)ternally- so re5uirin& clients of &un*tion to have e)plicit knowled&e of its e)istence violates encapsulation! Second- it re5uires the user to know the type of every function they want to store inside the 8unction class! 'n the case of 5lam$;o800<i+els this is rather simple- #ut suppose we want to store bindEnd(multi$lies int)(), 8CD) inside of &un*tion! 0hat is the type of the o#*ect returned #y bindEnd(multi$lies int)(), 8CD)> 8or reference- it's binderEnd multi$lies int) )- so if we wanted to store this in a 8unction we'd have to write
&un*tion m%&un*tion = ne' 6$e*ifi*&un*tion binderEnd multi$lies int) ) )(bindEnd(multi$lies int)(),8CD));

This is a syntactic ni&htmare and makes the &un*tion class terri#ly unattractive! 8ortunately- however- this pro#lem has a 5uick fi) ( we can rewrite the &un*tion constructor as a template function parameterized over the type of ar&ument passed into it- then construct the relevant 6$e*ifi*&un*tion for the &un*tion client! Since C++ automatically infers the parameter types of template functions- this means that clients of 8unction never need to know the type of what they're storin& ( the compiler will do the work for them! J)cellentR 'f we do end up makin& the 8unction constructor a template- we should also move the (nt&un*tion and 6$e*ifi*&un*tion classes so that they're inner classes of &un*tion! ,fter all- they're specific to the implementation of 8unction and the outside world has no #usiness usin& them! The updated interface for the &un*tion class is shown here=
*lass &un*tion { $ubli*4 "3 5onstru*tor and destru*tor. 3" tem$late t%$ename @nar%&un*tion) &un*tion(@nar%&un*tion fn); c&un*tion(); "3 5o$% su$$ort. 3" &un*tion(*onst &un*tion? other); &un*tion? o$erator= (*onst &un*tion? other); "3 &un*tion is a fun*tor that *alls into the stored resour*e. 3" int o$erator() (int value) *onst; $rivate4 *lass (nt&un*tion { "3 ... 3" #; tem$late t%$ename @nar%&un*tion) *lass 6$e*ifi*&un*tion { "3 ... 3" #; (nt&un*tion3 fun*tion; void *lear(); void *o$%=ther(*onst &un*tion? other);

#;

1 A1A 1 0e can then implement the constructor as follows=

Chapter /3& Functors

tem$late t%$ename @nar%&un*tion) &un*tion44&un*tion(@nar%&un*tion fn) { fun*tion = ne' 6$e*ifi*&un*tion @nar%&un*tion)(fn); #

Since we've left the &un*tion constructor not marked e)plicit- this template constructor is a conversion constructor! Coupled with the assi&nment operator- this means that we can use &un*tion as follows=
&un*tion fn = 5lam$;o800<i+els; *out fn(8CD) endl; "" <rints 800 *out fn(GE) endl; "" <rints GE fn = bindEnd(multi$lies int)(), E); *out fn(8CD) endl; "" <rints EDG *out fn(GE) endl; "" <rints FG

This is e)actly what we're lookin& for ( a class that can store any calla#le function that takes in an int and returns an int! 'f this doesn't strike you as a particularly ele&ant piece of code- take some time to look over it a&ain! There's one final step we should take- and that's to rela) the restriction that &un*tion always acts as a function from ints to ints! There's nothin& special a#out int- and #y &ivin& &un*tion clients the a#ility to specify their own parameter and return types we'll increase the scope of what &un*tion is capa#le of handlin&! 0e'll thus templatize &un*tion as &un*tion Arg;%$e, Ieturn;%$e)! 0e also need to make some minor edits to (nt&un*tion Kwhich we'll rename to Arbitrar%&un*tion since (nt&un*tion is no lon&er applica#leL- #ut in the interest of #revity we won't reprint them here! The final interface for &un*tion thus looks like this=
tem$late t%$ename Arg;%$e, t%$ename Ieturn;%$e) *lass &un*tion { $ubli*4 "3 5onstru*tor and destru*tor. 3" tem$late t%$ename @nar%&un*tion) &un*tion(@nar%&un*tion); c&un*tion(); "3 5o$% su$$ort. 3" &un*tion(*onst &un*tion? other); &un*tion? o$erator= (*onst &un*tion? other); "3 &un*tion is a fun*tor that *alls into the stored resour*e. 3" Ieturn;%$e o$erator() (Arg;%$e value) *onst; $rivate4 *lass Arbitrar%&un*tion { "3 ... 3" #; tem$late t%$ename @nar%&un*tion) *lass 6$e*ifi*&un*tion { "3 ... 3" # Arbitrar%&un*tion3 fun*tion; void *lear(); void *o$%=ther(*onst &un*tion? other);

#;

Chapter /3& Functors

1 A1? 1

To conclude our discussion of 2indo'- usin& the new &un*tion type we could rewrite the 2indo' class usin& &un*tion as follows=
*lass 2indo' { $ubli*4 2indo'(*onst &un*tion int, int)? 'idth&n, "3 ... 3" "3 ... other member fun*tions ... 3" $rivate4 &un*tion int, int) 'idth&un*tion; #;

"ow- clients can pass any unary function Kor functorL that maps from ints to ints as a parameter to 2indo' and the code will compile correctly! )*ternal !ol/mor+.ism The &un*tion type we've *ust developed is su#tle in its cleverness! 7ecause we can convert any calla#le unary function into a &un*tion- when writin& code that needs to work with some sort of unary functionwe can have that code use &un*tion instead of any specific function type! This techni5ue of a#stractin& away from the particular types that provide a #ehavior into an o#*ect representin& that #ehavior is sometimes known as e4ternal polymorphism! ,s opposed to internal polymorphism- where we e)plicitly define a set of classes containin& virtual functions- e)ternal polymorphism 4&rafts6 a set of virtual functions onto any type that supports the re5uisite #ehavior! Tirtual functions can #e sli&htly more e)pensive than re&ular functions #ecause of the virtual function ta#le lookup re5uired! J)ternal polymorphism is implemented usin& inheritance and thus also incurs an overhead- #ut the overhead is sli&htly &reater than re&ular inheritance! Think for a minute how the &un*tion class we *ust implemented is desi&ned! Callin& &un*tion44o$erator() re5uires the followin&= 1. 8ollowin& the Arbitrar%&un*tion pointer in the &un*tion class to its virtual function ta#le! 2. Callin& the function indicated #y the virtual function ta#le- which corresponds to the particular 6$e*ifi*&un*tion #ein& pointed at! 3. Callin& the actual function o#*ect stored inside the 6$e*ifi*&un*tion! This is sli&htly more comple) than a re&ular virtual function call- and illustrates the cost associated with e)ternal polymorphism! That said- in some cases Ksuch as the 8unction case outlined hereL the cost is overwhelmin& offset #y the fle)i#ility afforded #y e)ternal polymorphism! Im+lementing t.e 2functional: =ibrar/ "ow what we've seen how the fun*tional) li#rary works from a client perspective- let's discuss how the li#rary is put to&ether! 0hat's so special a#out adapta#le functions> /ow does $trLfun convert a re&ular function into an adapta#le one> /ow do functions like bindEnd and not8 work> This discussion will #e hi&hly technical and will push the limits of your knowled&e of templates- #ut #y the time you're done you should have an e)cellent &rasp of how template li#raries are put to&ether! Boreover- the techni5ues used here are applica#le #eyond *ust the fun*tional) li#rary and will almost certainly come in handy later in your pro&rammin& career!

1 A16 1

Chapter /3& Functors

et's #e&in #y lookin& at e)actly what an adapta#le function is! Fecall that adapta#le functions are functors that inherit from either unar%Lfun*tion or binar%Lfun*tion! "either of these template classes are particularly complicatedQ here's the complete definition of unar%Lfun*tion=P
tem$late t%$ename Arg;%$e, t%$ename Iet;%$e) *lass unar%Lfun*tion { $ubli*4 t%$edef Arg;%$e argumentLt%$e; t%$edef Iet;%$e resultLt%$e; #;

This class contains no data mem#ers and no mem#er functions! 'nstead- it e)ports two t%$edefs ( one renamin& Arg;%$e to argumentLt%$e and one renamin& Iet;%$e to resultLt%$e! 0hen you create an adapta#le function that inherits from unar%Lfun*tion- your class ac5uires these t%$edefs! 8or e)ampleif we write the followin& adapta#le function=
*lass (s<ositive4 $ubli* unar%Lfun*tion double, bool) { $ubli*4 bool o$erator() (double value) *onst { return value ) 0.0; # #;

The statement $ubli* unar%Lfun*tion double, double) imports two t%$edefs into (s<ositive= argumentLt%$e and returnLt%$e- e5ual to double and bool- respectively! Fi&ht now it mi&ht not #e apparent how these types are useful- #ut as we #e&in implementin& the other pieces of the fun*tional) li#rary it will #ecome more apparent! Im+lementing not1 To #e&in our #ehind1the1scenes tour of the fun*tional) li#rary- let's see how to implement the not8 function! Fecall that not8 accepts as a parameter a unary adapta#le predicate function- then returns a new adapta#le function that yields opposite values as the ori&inal function! 8or e)amplenot8((s<ositive()) would return a function that returns whether a value is not positive! 'mplementin& not8 re5uires two steps! 8irst- we'll create a template functor class parameterized over the type of the adapta#le function to ne&ate! This functor's constructor will take as a parameter an adapta#le function of the proper type and store it for later use! 0e'll then implement its o$erator() function such that it calls the stored function and returns the ne&ation of the result! 3raphically- this is shown here=

N+gation F0n*tor
In/0t Stor+d 50n*tion In3+rt+r O0t/0t

Gnce we have desi&ned this functor- we'll have not8 accept an adapta#le function- wrap it in our ne&atin& functor- then return the resultin& o#*ect to the caller! This means that the return value of not8 is an adapta#le unary predicate function that returns the opposite value of its parameter- which is e)actly what we want!

P Technically speakin& unar%Lfun*tion and binar%Lfun*tion are stru*ts- #ut this is irrelevant here!

Chapter /3& Functors

1 A1D 1

et's #e&in #y writin& the template functor class- which we'll call unar%Lnegate Kthis is the name of the functor class &enerated #y the fun*tional) li#rary's not8 functionL! 0e know that this functor should #e parameterized over the type of the adapta#le function it ne&ates- so we can #e&in #y writin& the followin&=
tem$late t%$ename @nar%<redi*ate) *lass unar%Lnegate { $ubli*4 e+$li*it unar%Lnegate(*onst @nar%<redi*ate? $red) 4 $($red) {# "3 ... 3" $rivate4 @nar%<redi*ate $; #;

/ere- the constructor accepts an o#*ect of type @nar%<redi*ate- then stores it in the data mem#er $! "ow- let's implement the o$erator() function- which- as you'll recall- should take in a parameter- feed it into the stored function $- then return the inverse result! The code for this function looks like this=
tem$late t%$ename @nar%<redi*ate) *lass unar%Lnegate { $ubli*4 e+$li*it unar%Lnegate(*onst @nar%<redi*ate? $red) 4 $($red) {# bool o$erator() (*onst /G what goes here! G/? $aram) *onst { return 1$($aram); "" 5all fun*tion and return the o$$osite result. # $rivate4 @nar%<redi*ate $; #;

0e've almost finished writin& our unar%Lnegate class- #ut we have a sli&ht pro#lem ( what is the type of the parameter to o$erator()> This is where adapta#le functions come in! 7ecause @nar%<redi*ate is adapta#le- it must e)port a type called argumentLt%$e correspondin& to the type of its ar&ument! 0e can thus define our o$erator() function to accept a parameter of type t%$ename @nar%<redi*ate44argume ntLt%$e to &uarantee that it has the same parameter type as the @nar%<redi*ate class!P The updated code for unar%Lnegate looks like this=
tem$late t%$ename @nar%<redi*ate) *lass unar%Lnegate { $ubli*4 e+$li*it unar%Lnegate(*onst @nar%<redi*ate? $red) 4 $($red) {# bool o$erator() (*onst t%$ename @nar%<redi*ate44argumentLt%$e? $aram) *onst { return 1$($aram); "" 5all stored fun*tion and return o$$osite result. # $rivate4 @nar%<redi*ate $; #;

That's 5uite a mouthful- #ut it's e)actly the solution we're lookin& for! 'f it weren't for the fact that @nar%<redi*ate is an adapta#le function- we would not have #een a#le to determine the parameter type for the o$erator() mem#er function- and code like this would not have #een possi#le!
P Femem#er that the type is t%$ename @nar%<redi*ate44argumentLt%$e- not @nar%<redi*ate44argumentLt%$e! argumentLt%$e is nested inside @nar%<redi*ate- and since @nar%<redi*ate is a template ar&ument we have to e)plicitly use t%$ename to indicate that argumentLt%$e is a type!

1 A1E 1

Chapter /3& Functors

There's one step left to finalize this functor class- and that's to make the functor into an adapta#le function #y havin& it inherit from the proper unar%Lfun*tion! Since the functor's ar&ument type is t%$ename @nar%<redi*ate44argumentLt%$e and its return type is bool- we'll inherit from unar%Lfun*tion t%$ename @nar%<redi*ate44 argumentLt%$e, bool)! The final code for unar%Lnegate is shown here=
tem$late t%$ename @nar%<redi*ate) *lass unar%Lnegate4 $ubli* unar%Lfun*tion t%$ename @nar%<redi*ate44argumentLt%$e, bool) { $ubli*4 e+$li*it unar%Lnegate(*onst @nar%<redi*ate? $red) 4 $($red) {# bool o$erator() (*onst t%$ename @nar%<redi*ate44argumentLt%$e? $aram) *onst { return 1$($aram); "" 5all stored fun*tion and return o$$osite result. # $rivate4 @nar%<redi*ate $; #;

0e've now finished writin& our functor class to perform the ne&ation- and all that's left to do is write not8! not8 is much simpler than unar%Lnegate- since it simply has to take in a parameter and wrap it in a unar%Lnegate functor! This is shown here=
tem$late t%$ename @nar%<redi*ate) unar%Lnegate @nar%<redi*ate) not8(*onst @nar%<redi*ate? $red) { return unar%Lnegate @nar%<redi*ate)($red); #

That's all there is to it ( we've successfully implemented not8R .ou mi&ht #e wonderin& why there are two steps involved in writin& not8! ,fter all- once we have the functor that performs ne&ation- why do we need to write an additional function to create it> The answer is simplicity! 0e don't need not8- #ut havin& it availa#le reduces comple)ity! 8or e)ample- usin& the (s<ositive adapta#le function from a#ove- let's suppose that we want to write code to find the first nonpositive element in a ve*tor! Usin& the findLif al&orithm and not8- we'd write this as follows=
ve*tor double)44iterator itr = findLif(v.begin(), v.end(), not8((s<ositive()));

'f instead of usin& not8 we were to e)plicitly create a unar%Lnegate o#*ect- the code would look like this=
ve*tor double)44iterator itr = findLif(v.begin(), v.end(), unar%Lnegate (s<ositive)((s<ositive()));

That's 5uite a mouthful! 0hen callin& the template function not8- the compiler automatically infers the type of the ar&ument and constructs an appropriately parameterized unar%Lnegate o#*ect! 'f we directly use unar%Lnegate- C++ will not perform type inference and we'll have to spell out the template ar&uments ourselves! The pattern illustrated here ( havin& a template class and a template function to create it ( is common in li#rary code #ecause it lets li#rary clients use comple) classes without ever havin& to know how they're implemented #ehind1the1scenes!

Chapter /3& Functors Im+lementing ptr8fun

1 A1< 1

"ow that we've seen how not8 works- let's see if we can construct the $trLfun function! ,t a hi&h level $trLfun and not8 work the same way ( they each accept a parameter- construct a special functor class #ased on the parameter- then return it to the caller! The difference #etween not8 and $trLfun- howeveris that there are two different versions of $trLfun ( one for unary functions and one for #inary functions! The two versions work almost identically and we'll see how to implement them #oth- #ut for simplicity we'll #e&in with the unary case! To convert a raw C++ unary function into an adapta#le unary function- we need to wrap it in a functor that inherits from the proper unar%Lfun*tion #ase class! 0e'll make this functor's o$erator() function simply call the stored function and return its value! To #e consistent with the namin& convention of the fun*tional) li#rary- we'll call the functor $ointerLtoLunar%Lfun*tion and will parameterize it over the ar&ument and return types of the function! This is shown here=
tem$late t%$ename Arg;%$e, t%$ename Iet;%$e) *lass $ointerLtoLunar%Lfun*tion4 $ubli* unar%Lfun*tion Arg;%$e, Iet;%$e) { $ubli*4 e+$li*it $ointerLtoLunar%Lfun*tion(Arg;%$e fn(Iet;%$e)) 4 fun*tion(fn) {# Iet;%$e o$erator() (*onst Arg;%$e? $aram) *onst { return fun*tion($aram); # $rivate4 Arg;%$e (3fun*tion)(Iet;%$e); #;

There isn't that much code here- #ut it's fairly dense! "otice that we inherit from unar%Lfun*tion Arg;%$e, Iet;%$e) so that the resultin& functor is adapta#le! ,lso note that the ar&ument and return types of o$erator() are considera#ly easier to determine than in the unar%Lnegate case #ecause they're specified as template ar&uments! "ow- how can we implement $trLfun to return a correctly1constructed $ointerLtoLunar%Lfun*tion> Simple ( we *ust write a template function parameterized over ar&ument and return types- accept a function pointer of the appropriate type- then wrap it in a $ointerLtoLunar%Lfun*tion o#*ect! This is shown here=
tem$late t%$ename Arg;%$e, t%$ename Iet;%$e) $ointerLtoLunar%Lfun*tion Arg;%$e, Iet;%$e) $trLfun(Iet;%$e fun*tion(Arg;%$e)) { return $ointerLtoLunar%Lfun*tion Arg;%$e, Iet;%$e)(fun*tion); #

This code is fairly dense- #ut &ets the *o# done! The implementation of $trLfun for #inary functions is similar to the implementation for unary functions! 0e'll create a template functor called $ointerLtoLbinar%Lfun*tion parameterized over its ar&ument and return types- then provide an implementation of $trLfun that constructs and returns an o#*ect of this type! This is shown here=

1 A;0 1

Chapter /3& Functors

tem$late t%$ename Arg8, t%$ename ArgE, t%$ename Iet) *lass $ointerLtoLbinar%Lfun*tion4 $ubli* binar%Lfun*tion Arg8, ArgE, Iet) { $ubli*4 e+$li*it $ointerLtoLbinar%Lfun*tion(Iet fn(Arg8, ArgE)) 4 fun*tion(fn) {# Iet o$erator() (*onst Arg8? arg8, *onst ArgE? argE) *onst { return fun*tion(arg8, argE); # $rivate4 Iet (3fun*tion)(Arg8, ArgE); #; tem$late t%$ename Arg8, t%$ename ArgE, t%$ename Iet) $ointerLtoLbinar%Lfun*tion Arg8, ArgE, Iet) $trLfun(Iet fun*tion(Arg8, ArgE)) { return $ointerLtoLbinar%Lfun*tion Arg8, ArgE, Iet)(fun*tion); #

"ote that we now have two versions of $trLfun ( one that takes in a unary function and one that takes in a #inary function! 8ortunately- C++ overloadin& rules allow for the two functions to coe)ist- since they have different si&natures! Im+lementing bind1st To wrap up our tour of the fun*tional) li#rary- let's see how to implement bind8st! 'f you'll recallbind8st takes in a #inary adapta#le function and a value- then returns a new unary function e5ual to the input function with the first parameter locked in place! 0e'll follow the pattern of not8 and $trLfun #y writin& a template functor class called binder8st that actually does the #indin&- then havin& bind8st construct and return an o#*ect of the proper type! 7efore proceedin& with our implementation of binder8st- we need to take a 5uick detour into the inner workin&s of the binar%Lfun*tion class! ike unar%Lfun*tion- binar%Lfun*tion e)ports t%$edefs so that other parts of the fun*tional) li#rary can recover the ar&ument and return types of adapta#le functions! /owever- since a #inary function has two ar&uments- the names of the e)ported types are sli&htly different! binar%Lfun*tion provides the followin& three t%$edefs=
first8argument8type- the type of the first ar&umentsecond8argument8type- the type of the second ar&ument- and result8type- the function's return type!

0e will need to reference each of these type names when writin& bind8st! "ow- how do we implement the binder8st functor> /ere is one possi#le implementation! The binder8st constructor will accept and store an adapta#le #inary function and the value for its first ar&ument! binder8st then provides an implementation of o$erator() that takes a sin&le parameterthen invokes the stored function passin& in the function parameter and the saved value! This is shown here=

Chapter /3& Functors

1 A;1 1

,inding F0n*tor
Stor+d F0n*tion
Stor+d 7a-0+ Param Param !

O0t/0t

In/0t

et's #e&in implementin& binder8st! The functor has to #e a template- since we'll #e storin& an ar#itrary adapta#le function and value! /owever- we only need to parameterize the functor over the type of the #inary adapta#le function- since we can determine the type of the first ar&ument from the adapta#le function's firstLargumentLt%$e! 0e'll thus #e&in with the followin& implementation=
tem$late t%$ename Pinar%&un*tion) *lass binder8st { "3 ... 3" #;

"ow- let's implement the constructor! 't should take in two parameters ( one representin& the #inary function and the other the value to lock into place! The first will have type Pinar%&un*tionQ the secondt%$ename Pinar%&un*tion44firstLargumentLt%$e! This is shown here=
tem$late t%$ename Pinar%&un*tion) *lass binder8st { $ubli*4 binder8st(*onst Pinar%&un*tion? fn, *onst t%$ename Pinar%&un*tion44firstLargumentLt%$e? arg) 4 fun*tion(fn), first(arg) {# "3 ... 3" $rivate4 Pinar%&un*tion fun*tion; t%$ename Pinar%&un*tion44firstLargumentLt%$e first; #;

ChewR That's 5uite a mouthful- #ut is the reality of much li#rary template code! Boo0 at the declaration o* the first data member. Tho#/h it may seem stran/e, this is the correct way to declare a data member whose type is a type nested inside a template ar/#ment. 0e now have the constructor written and all that's left to take care of is o$erator()! Conceptually- this function isn't very difficult- and if we i&nore the parameter and return types have the followin& implementation=

1 A;; 1

Chapter /3& Functors

tem$late t%$ename Pinar%&un*tion) *lass binder8st { $ubli*4 binder8st(*onst Pinar%&un*tion? fn, *onst t%$ename Pinar%&un*tion44firstLargumentLt%$e? arg) 4 fun*tion(fn), first(arg) {# "3 ret 3" o$erator() (*onst "3 arg 3"? $aram) *onst { return fun*tion(first, $aram); # $rivate4 Pinar%&un*tion fun*tion; t%$ename Pinar%&un*tion44firstLargumentLt%$e first;

#;

0hat are the ar&ument and return types for this function> 0ell- the function returns whatever o#*ect is produced #y the stored function- which has type t%$ename Pinar%&un*tion44resultLt%$e! The function accepts a value for use as the second parameter to the stored function- so it must have type t%$ename Pinar%&un*tion44 se*ondLargumentLt%$e! This results in the followin& code=
tem$late t%$ename Pinar%&un*tion) *lass binder8st { $ubli*4 binder8st(*onst Pinar%&un*tion? fn, *onst t%$ename Pinar%&un*tion44firstLargumentLt%$e? arg) 4 fun*tion(fn), first(arg) {# t%$ename Pinar%&un*tion44resultLt%$e o$erator() (*onst t%$ename Pinar%&un*tion44se*ondLargumentLt%$e? $aram) *onst { return fun*tion(first, $aram); # $rivate4 Pinar%&un*tion fun*tion; t%$ename Pinar%&un*tion44firstLargumentLt%$e first; #;

0e're almost finished- and all that's left for binder8st is to make it adapta#le! Usin& the lo&ic from a#ovewe'll have it inherit from the proper instantiation of unar%Lfun*tion- as shown here=
tem$late t%$ename Pinar%&un*tion) *lass binder8st 4 $ubli* unar%Lfun*tion t%$ename Pinar%&un*tion44se*ondLargumentLt%$e, t%$ename Pinar%&un*tion44resultLt%$e) { $ubli*4 binder8st(*onst Pinar%&un*tion? fn, *onst t%$ename Pinar%&un*tion44firstLargumentLt%$e? arg) 4 fun*tion(fn), first(arg) {# t%$ename Pinar%&un*tion44resultLt%$e o$erator() (*onst t%$ename Pinar%&un*tion44se*ondLargumentLt%$e? $aram) *onst { return fun*tion(first, $aram); # $rivate4 Pinar%&un*tion fun*tion; t%$ename Pinar%&un*tion44firstLargumentLt%$e first; #;

That's it for the binder8st class! ,s you can see- the code is dense and does a lot of ma&ic with t%$ename and nested types! 0ithout adapta#le functions- code like this would not #e possi#le! To finish up our discussion- let's implement bind8st! This function isn't particularly tricky- thou&h we do need to do a #it of work to e)tract the type of the value to lock in place=

Chapter /3& Functors


tem$late t%$ename Pinar%&un*tion) binder8st Pinar%&un*tion) bind8st(*onst Pinar%&un*tion? fn, *onst t%$ename Pinar%&un*tion44firstLargumentLt%$e? arg) { return binder8st Pinar%&un*tion)(fn, arg); #

1 A;@ 1

0e now have a complete workin& implementation of bind8st! 'f you actually open up the fun*tional) header and peek around inside- the code you'll find will pro#a#ly #ear a stron& resem#lance to what we've written here! =imitations of t.e 2unctional =ibrar/ 0hile the ST functional li#rary is useful in a wide num#er of cases- the li#rary is unfortunately 5uite limited! fun*tional) only provides support for adapta#le unary and #inary functions- #ut commonly you'll encounter situations where you will need to #ind and ne&ate functions with more than two parameters! 'n these cases- one of your only options is to construct functor classes that accept the e)tra parameters in their constructors! Similarly- there is no support for function composition- so we could not create a function that computes ;4 + 1 #y callin& the appropriate com#ination of the plus and multiplies functors! /owever- the ne)t version of C++- nicknamed 4C++0)-6 promises to have more support for functional pro&rammin& of this sort! 8or e)ample- it will provide a &eneral function called bind that lets you #ind as many values as you'd like to a function of ar#itrary arity! Keep your eyes peeled for the ne)t release of C++ ( it will #e far more functional than the current versionR !ractice !roblems 0e've covered a lot of pro&rammin& techni5ues in this chapter and there are no shorta&e of applications for the material! /ere are some pro#lems to &et you thinkin& a#out how functors and adapta#le functions can influence your pro&rammin& style= 1. 0hat is a functor> 2. 0hat restrictions- if any- e)ist on the parameter or return types of o$erator()> 3. 0hy are functors more powerful than re&ular functions> 4. /ow do you define a function that can accept #oth functions and functors as parameters> . 0hat is an adapta#le function> !. /ow do you convert a re&ular C++ function into an adapta#le function> $. 0hat does the bind8st function do> 6. 0hat does the notE function do> 7. The ST al&orithm forLea*h accepts as parameters a ran&e of iterators and a unary function- then calls the function on each ar&ument! Unusually- the return value of forLea*h is the unary function passed in as a parameter! 0hy mi&ht this #e>

1 A;A 1

Chapter /3& Functors

10. Usin& the fact that forLea*h returns the unary function passed as a parameter- write a function :%A**umulate that accepts as parameters a ran&e of ve*tor int)44iterators and an initial value- then returns the sum of all of the values in the ran&e- startin& at the specified value! 2o not use any loops ( instead- use forLea*h and a custom functor class that performs the addition! 11. 0rite a function Advan*edPiased6ort that accepts as parameters a ve*tor string) and a string 4winner6 value- then sorts the ran&e- e)cept that all strin&s e5ual to the winner are at the front of the ve*tor! 2o not use any loops! 5+int& 2se the ,TL sort algorithm and $unctor that stores the EwinnerF parameter 6 12. Bodify the a#ove implementation of Advan*edPiased6ort so that it works over an ar#itrary ran&e of iterators over strin&s- not *ust a ve*tor string)! Then modify it once more so that the iterators can iterate over any type of value! 13. The ST
generate al&orithm is defined as void generate(&or'ard(terator start, &or'ard(terator end, Kullar%&un*tion fn) and iterates over the specified ran&e storin& the return value of the zero1parameter function fn as it &oes! 8or e)ample- callin& generate(v.begin(), v.end(), rand) would fill the ran&e Nv.begin() to v.end()L with random values! 0rite a function &illAs*ending that accepts an iterator ran&e- then sets the first

element in the ran&e to zero- the second to one- etc! 2o not use any loops!

14. 0rite a function E+$unge7etter that accepts four parameters ( two iterators delineatin& an input ran&e of strings- one iterator delineatin& the start of an output ran&e- and a character ( then copies the strin&s in the input ran&e that do not contain the specified character into the output ran&e! The function should then return an iterator one past the last location written! 2o not use loops! 5+int& 2se the remo#e%copy%if algorithm and a custom $unctor6 1 . The standard deviation of a set of data is a measure of how much the data varies from its avera&e value! 2ata with a small standard deviation tends to cluster around a point- while data with lar&e standard deviation will #e more spread out! The formula for the standard deviation of a set of data ] 41- 4;- !!!- 4n^ is

1 x i x 2 n i =1

/ere- 4 is the avera&e of the data points! To &ive a feelin& for this formula- &iven the data points 1- ;- @- the avera&e of the data points is ;- so the standard deviation is &iven #y

1 1 1 1 2 x i x 2 = x i 2 2= 1 2 2 2 2 2 32 2 = 1 0 1= n 3 3 3 3 i =1 i=1

0rite a function 6tandard9eviation that accepts an input ran&e of iterators over doubles Kor values implicitly converti#le to doublesL and returns its standard deviation! 2o not use any loops ( instead use the a**umulate function to compute the avera&e- then use a**umulate once more to compute the sum! 5+int& To get the number o$ elements in the range, you can use the distance $unction6

Chapter /3& Functors

1 A;? 1

1!. 0rite a function 5learAll6trings that accepts as input a ran&e of iterators over strings that sets each strin& to #e the empty strin&! 'f you harness the fun*tional) li#rary correctly herethe function #ody will #e only a sin&le line of code! 1$. The FGT1;E cipher is a weak encryption cipher that works #y addin& 1;E to the value of each character in a strin& to produce a &ar#led strin&! Since *har can only hold ;?6 different valuestwo successive applications of FGT1;E will produce the ori&inal strin&! 0rite a function A$$l%I=;8EF that accepts a string and returns the string's FGT1;E cipher e5uivalent! 16. 0rite a template function 5a$AtJalue that accepts a ran&e of iterators and a value #y reference1 to1*onst and replaces all elements in the ran&e that compare &reater than the parameter with a copy of the parameter! 5+int& use the replace%if algorithm6 17. Gne piece of functionality missin& from the fun*tional) li#rary is the a#ility to #ind the first parameter of a unary function to form a nullary function! 'n this practice pro#lem- we'll implement a function called Pind=nl% that transforms a unary adapta#le function into a nullary function! a. 0rite a template functor class Pinder=nl% parameterized whose constructor accepts an adapta#le function and a value to #ind and whose o$erator() function calls the stored function passin& in the stored value as a parameter! .our class should have this interface=
tem$late t%$ename @nar%&un*tion) *lass Pinder=nl% { $ubli*4 Pinder=nl%(*onst @nar%&un*tion? fn, *onst t%$ename @nar%&un*tion44argumentLt%$e? value); Iet;%$e o$erator() () *onst; #;

b. 0rite a template function Pind=nl% that accepts the same parameters as the Pinder=nl% constructor and returns a Pinder=nl% of the proper type! The si&nature for this function should #e
tem$late t%$ename @nar%&un*tion) Pinder=nl% @nar%&un*tion) Pind=nl%(*onst @nar%&un*tion ?fn, *onst t%$ename @nar%&un*tion44argumentLt%$e? value);

20. ,nother operation not supported #y the Vfunctional_ li#rary is $unction composition! 8or e)ample&iven two functions f and g- the composition g e f is a function such that g e fK)L Y gKfK)LL! 'n this e)ample- we'll write a function Compose that lets us compose two unary functions of compati#le types! a. 0rite a template functor @nar%5om$ose parameterized over two adapta#le function types whose constructor accepts and stores two unary adapta#le functions and whose o$erator() accepts a sin&le parameter and returns the composition of the two functions applied to that ar&ument! Bake sure that @nar%5om$ose is an adapta#le unary function! b. 0rite a wrapper function 5om$ose that takes in the same parameters as @nar%5om$ose and returns a properly1constructed @nar%5om$ose o#*ect! c. J)plain how to implement not8 usin& 5om$ose and logi*alLnot- a unary adapta#le function e)ported #y fun*tional) that returns the lo&ical inverse of its ar&ument!

!art T.ree
(ore to )*+lore
Hhew1 Oo#.ve made it thro#/h the *irst three sections and are now a seasoned and competent "LL pro/rammer. &#t yo#r Ao#rney has A#st be/#n. There are many parts o* the "LL pro/rammin/ lan/#a/e that we have not covered, and it.s now #p to yo# to be/in the rest o* yo#r Ao#rney. This last section o* the boo0 contains two chapters. The *irst, on "LL04, disc#sses what chan/es are e4pected *or the "LL pro/rammin/ lan/#a/e over the ne4t *ew years. -ow that yo#.ve seen "LL.s stren/ths and wea0nesses, 2 hope that this chapter proves enli/htenin/ and e4citin/. The second chapter is all abo#t how to contin#e yo#r Ao#rney into *#rther "LL mastery and hope*#lly can /ive yo# a boost in the ri/ht direction.

C.a+ter 1'8 C99-*


_________________________________________________________________________________________________________

C++%4 $eels li*e a new language& The pieces !ust $it together better than they used to and I $ind a higher"level style o$ programming more natural than be$ore and as e$$icient as ever I$ you timidly approach C++ as !ust a better C or as an ob!ect"oriented language, you are going to miss the point The abstractions are simply more $le4ible and a$$ordable than be$ore Gely on the old mantra& I$ you thin* LoM$ it as a separate idea or ob!ect, represent it directly in the programN model real"world ob!ects, concepts, and abstractions directly in code It)s easier now& Jour ideas will map to enumerations, ob!ects, classes 5e g control o$ de$aults6, class hierarchies 5e g inherited constructors6, templates, concepts, concept maps, a4ioms, aliases, e4ceptions, loops, threads, etc , rather than to a single Eone si8e $its allF abstraction mechanism -y ideal is to use programming language $acilities to help programmers thin* di$$erently about system design and implementation I thin* C++%4 can do that > and do it not !ust $or C++ programmers but $or programmers used to a variety o$ modern programming languages in the general and very broad area o$ systems programming In other words, I)m still an optimist ( 7*arne Stroustrup- inventor of C++! NStr0<!@O C++ is constantly evolvin&! Gver the past few years the C++ standards #ody has #een developin& the ne)t revision of C++- nicknamed C++%4! C++0) is a ma*or up&rade to the C++ pro&rammin& lan&ua&e and as we wrap up our tour of C++- ' thou&ht it appropriate to conclude #y e)plorin& what C++0) will have in store! This chapter covers some of the more impressive features of C++0) and what to e)pect in the future! 7e aware that C++0) has not yet #een finalized- and the material in this chapter may not match the final C+ +0) specification! /owever- it should #e a &reat launchin& point so that you know where to look to learn more a#out the ne)t release of C++! Automatic T/+e Inference Consider the followin& piece of code=
void 9o6omething(*onst multima$ string, ve*tor int) )? m%:a$) { *onst $air multima$ string, ve*tor int) )44*onstLiterator, multima$ string, ve*tor int) )44*onstLiterator) e[ = m%:a$.e[ualLrange(/6tring1/); for(multima$ string, ve*tor int) )44*onstLiterator itr = e[.first; itr 1= e[.se*ond; !!itr) *out itr-)siUe() endl; #

This a#ove code takes in a multima$ mappin& from strings to ve*tor int)s and prints out the len&th of all vectors in the multima$ whose key is 4Strin&R6 0hile the code is perfectly le&al C++- it is e)tremely difficult to follow #ecause more than half of the code is spent listin& the types of two varia#les- e[ and itr! 'f you'll notice- these varia#les can only take on one type ( the type of the e)pression used to initialize them! Since the compiler knows all of the types of the other varia#les in this code snippet- couldn't we *ust ask the compiler to &ive e[ and itr the ri&ht types> 8ortunately- in C++0)- the answer is yes thanks to a

1 A@0 1

Chapter /7& C++%4

new lan&ua&e feature called type in$erence! Usin& type inference- we can rewrite the a#ove function in a#out half as much space=
void 9o6omething(*onst multima$ string, ve*tor int))? m%:a$) { *onst auto e[ = m%:a$.e[ualLrange(/6tring1/); for(auto itr = e[.first; itr 1= e[.se*ond; !!itr) *out itr-)siUe() endl; #

"otice that we've replaced all of the #ulky types in this e)pression with the keyword auto- which tells the C++0) compiler that it should infer the proper type for a varia#le! The standard iterator loop is now considera#ly easier to write- since we can replace the clunky multima$ string, ve*tor int) )44*onstLiterator with the much simpler auto! Similarly- the hideous return type associated with e[ualLrange is entirely a#sent! 7ecause auto must #e a#le to infer the type of a varia#le from the e)pression that initializes it- you can only use auto when there is a clear type to assi&n to a varia#le! 8or e)ample- the followin& is ille&al=
auto +;

Since + could theoretically #e of any type!


auto is also useful #ecause it allows comple) li#raries to hide implementation details #ehind1the1scenes! 8or e)ample- recall that the $trLfun function from the ST fun*tional) li#rary takes as a parameter a

re&ular C++ function and returns an adapta#le version of that function! 'n our discussion of the li#rary's implementation- we saw that the return type of $trLfun is either $ointerLtoLunar%Lfun*tion Arg, Iet) or $ointerLtoLbinar%Lfun*tion Arg8, ArgE, Iet)- dependin& on whether the parameter is a unary or #inary function! This means that if you want to use $trLfun to create an adapta#le function and want to store the result for later use- usin& current C++ you'd have to write somethin& to the effect of
$ointerLtoLunar%Lfun*tion int, bool) ou*hies = $trLfun(6ome&un*tion);

This is terri#ly hard to read #ut more importantly #reaks the wall of a#straction of $trLfun! The entire purpose of $trLfun is to hide the transformation from function to functor- and as soon as you are re5uired to know the return type of $trLfun the #enefits of the automatic wrappin& facilities vanish! 8ortunatelyauto can help maintain the a#straction- since we can rewrite the a#ove as
auto ho'Ki*e = $trLfun(6ome&un*tion);

C++0) will provide a companion operator to auto called de*lt%$e that returns the type of a &iven e)pression! 8or e)ample- de*lt%$e(8 ! E) will evaluate to int- while de*lt%$e(ne' *har) will #e *har 3! de*lt%$e does not evaluate its ar&ument ( it simply yields its type ( and thus incurs no cost at runtime! Gne potential use of de*lt%$e arises when writin& template functions! 8or e)ample- suppose that we want to write a template function as follows=
tem$late t%$ename ;) "3 some t%$e 3" :%&un*tion(*onst ;? val) { return val.do6omething(); #

This function accepts a ; as a template ar&ument- invokes that o#*ect's do6omething mem#er functionthen returns its value Knote that if the type ; doesn't have a mem#er function do6omething- this results in

Chapter /7& C++%4

1 A@1 1

a compile1time errorL! 0hat should we use as the return type of this function> 0e can't tell #y simply lookin& at the type ;- since the do6omething mem#er function could theoretically return any type! /owever- #y usin& de*lt%$e and a new function declaration synta)- we can rewrite this as
tem$late t%$ename ;) auto :%&un*tion(*onst ;? val) -: decltype3#al.doIomething344 { return val.do6omething(); #

"otice that we defined the function's return type as auto- and then after the parameter list said that the return type is de*lt%$e(val.do6omething())! This new synta) for function declarations is optional#ut will make complicated function prototypes easier to read! (o;e 6emantics 'f you'll recall from our discussion of copy constructors and assi&nment operators- when returnin& a value from a function- C++ initializes the return value #y invokin& the class's copy constructor! 0hile this method &uarantees that the returned value is always valid- it can #e &rossly inefficient! 8or e)ampleconsider the followin& code=
ve*tor string) 7oadAll2ords(*onst string? filename) { ifstream in$ut(filename.*Lstr()); if(1in$ut.isLo$en()) thro' runtimeLerror(/&ile not found1/); "3 @se the ve*torAs insert fun*tion, $lus some istreamLiterators, to 3 load the *ontents of the file. 3" ve*tor string) result; result.insert(result.begin(), istreamLiterator string)(in$ut), istreamLiterator string)()); return result; #

/ere- we open the file specified #y filename- then use a pair of istreamLiterators to load the contents of the file into the ve*tor! ,t the end of this function- #efore the return result statement e)ecutes- the memory associated with the result ve*tor looks somethin& like this Kassumin& a ve*tor is implemented as a pointer to a raw C++ arrayL= Al$ha result elems len 8CD Peta Gamma ... 5hi <si =mega "ow- the statement return result e)ecutes and C++ initializes the return value #y invokin& the ve*tor copy constructor! ,fter the copy the pro&ram's memory looks like this=

1 A@; 1

Chapter /7& C++%4

result
elems len 8CD

Al$ha Peta Gamma ... 5hi <si =mega

return #alue
elems len 8CD

Al$ha Peta Gamma ... 5hi <si =mega

,fter the return value is initialized- result will &o out of scope and its destructor will clean up its memory! Bemory now looks like this= Al$ha return #alue elems len 8CD Peta Gamma ... 5hi <si =mega /ere- we made a full deep copy of the contents of the returned o#*ect- then deallocated all of the ori&inal memory! This is inefficient- since we needlessly copied a lon& list of strin&s! There is a much #etter way to return the ve*tor from the function! 'nstead of initializin& the return value #y makin& a deep copyinstead we'll make it a shallow copy of ve*tor we're returnin&! The in1memory representations of these two vectors thus look like this= Al$ha result return #alue elems len 8CD Peta Gamma ... 5hi <si =mega ,lthou&h the two vectors share the same memory- the returned ve*tor has the same contents as the source ve*tor and is in fact indistin&uisha#le from the ori&inal! 'f we then modify the ori&inal ve*tor #y detachin& its pointer from the array and havin& it point to K@77 Kor- since this is C++0)- the special value null$trL- then we end up with a picture like this= 8CD len elems

Chapter /7& C++%4

1 A@@ 1

result
elems len
null$tr

Al$ha Peta Gamma ... 5hi <si =mega

return #alue
elems 8CD len

"ow- result is an empty ve*tor whose destructor will not clean up any memory- and the callin& function will end up with a ve*tor whose contents are e)actly those returned #y the function! 0e've successfully returned the value from the function- #ut avoided the e)pensive copy! 'n our case- if we have a ve*tor of n strings of len&th at most m- then the al&orithm for copyin& the ve*tor will take GKmnL! The al&orithm for simply transferrin& the pointer from the source ve*tor to the destination- on the other hand- is GK1L for the pointer manipulations! The difference #etween the current method of returnin& a value and this improved version of returnin& a value is the difference #etween copy semantics and move semantics ,n o#*ect has copy semantics if it can #e duplicated in another location! ,n o#*ect has move semantics Ka feature introduced in C++0)L if it can #e moved from one varia#le into another- destructively modifyin& the ori&inal! The key difference #etween the two is the num#er of copies at any point! Copyin& an o#*ect duplicates its data- while movin& an o#*ect transfers the contents from one o#*ect to another without makin& a copy! To support move semantics- C++0) introduces a new varia#le type called an rvalue re$erence whose synta) is ;%$e ??! 8or e)ample- an rvalue reference to a ve*tor int) would #e a ve*tor int) ??! 'nformallyyou can view an rvalue reference as a reference to a temporary o#*ect- especially one whose contents are to #e moved from one location to another! et's return to the a#ove e)ample with returnin& a ve*tor from a function! 'n the current version of C++we'd define a copy constructor and assi&nment operator for ve*tor to allow us to return ve*tors from functions and to pass ve*tors as parameters! 'n C++0)- we can optionally define another special functioncalled a move constructor- that initializes a new ve*tor #y movin& data out of one ve*tor into another! 'n the a#ove e)ample- we mi&ht define a move constructor for the ve*tor as follows=
"3 :ove *onstru*tor taBes a ve*tor?? as a $arameter, sin*e 'e 'ant to move 3 data from the $arameter into this ve*tor. 3" tem$late t%$ename ;) ve*tor ;)44ve*tor(#ectorPP other) { "3 2e $oint to the same arra% as other and have the same length. 3" elems = other.elems; len = other.len; "3 9estru*tivel% modif% the sour*e ve*tor to sto$ sharing the arra%. 3" other.elems = null$tr; other.len = 0; #

"ow- if we return a ve*tor from a function- the new ve*tor will #e initialized usin& the move constructor rather than the re&ular copy constructor! 0e can similarly define a move assignment operator Kas opposed to the traditional copy assi&nment operatorL- as shown here=

1 A@A 1

Chapter /7& C++%4

tem$late t%$ename ;) ve*tor ;)? ve*tor ;)44o$erator= (#ectorPP other) { if(this 1= ?other) { delete [] elems; elems = other.elems; len = other.len; "3 :odif% the sour*e ve*tor to sto$ sharing the arra%. 3" other.elems = null$tr; other.len = 0; # return 3this; #

The similarity #etween a copy constructor and copy assi&nment operator is also noticea#le here in the move constructor and move assi&nment operator! 'n fact- we can rewrite the pair usin& helper functions *lear and move=ther=
tem$late t%$ename ;) void ve*tor ;)44move=ther(ve*tor?? other) { "3 2e $oint to the same arra% as the other ve*tor and have the same 3 length. 3" elems = other.elems; len = other.len; "3 :odif% the sour*e ve*tor to sto$ sharing the arra%. 3" other.elems = null$tr; other.len = 0; # tem$late t%$ename ;) void ve*tor ;)44*lear() { delete [] elems; len = 0; # tem$late t%$ename ;) ve*tor ;)44ve*tor(ve*tor?? other) { move=ther(mo#e(other)); "" 6ee later se*tion for move # tem$late t%$ename ;) ve*tor ;)? ve*tor ;)44o$erator =(ve*tor?? other) { if(this 1= ?other) { *lear(); move=ther(mo#e(other)); # return 3this; #

Bove semantics are also useful in situations other than returnin& o#*ects from functions! 8or e)amplesuppose that we want to insert an element into an array- shufflin& all of the other values down one spot to make room for the new value! Usin& current C++- the code for this operation is as follows=
tem$late t%$ename ;) void (nsert(ntoArra%(;3 elems, int siUe, int $osition, *onst ;? toAdd) { for(int i = siUe; i ) $osition; !!i) elems[i] = elems[i Q 8]; "" 6huffle elements do'n. elems[i] = toAdd; #

Chapter /7& C++%4

1 A@? 1

There is nothin& wron& per se with this code as it's written- #ut if you'll notice we're usin& copy semantics to shuffle the elements down when move semantics is more appropriate! ,fter all- we don't want to copy the elements into the spot one element downQ we want to move them! 'n C++0)- we can use an o#*ect's move semantics Kif anyL #y usin& the special helper function movee)ported #y utilit%)- which simply returns an rvalue reference to an o#*ect! "ow- if we write
a = move(b);

'f a has support for move semantics- this will move the contents of b into a! 'f a does not have support for move semantics- however- C++ will simply fall #ack to the default o#*ect copy #ehavior usin& the assi&nment operator! 'n other words- supportin& move operations is purely optional and a class can still use the old fashioned copy constructor and assi&nment operator pair for all of its copyin& needs! /ere's the rewritten version of (nsert(ntoArra%- this time usin& move semantics=
tem$late t%$ename ;) void (nsert(ntoArra%(;3 elems, int siUe, int $osition, *onst ;? toAdd) { for(int i = siUe; i ) $osition; !!i) elems[i] = mo#e(elems[i Q 8]); "" :ove elements do'n. elems[i] = toAdd; #

Curiously- we can potentially take this one step further #y movin& the new element into the array rather than copyin& it! 0e thus provide a similar function- which we'll call :ove(ntoArra%- which moves the parameter into the specified position=
tem$late t%$ename ;) void :ove(ntoArra%(;3 elems, int siUe, int $osition, %PP toAdd) { for(int i = siUe; i ) $osition; !!i) elems[i] = mo#e(elems[i Q 8]); "" :ove elements do'n. "3 Kote that even though toAdd is an rvalue referen*e, 'e still must 3 e+$li*itl% move it in. ;his $revents us from a**identall% using 3 move semanti*s in a fe' edge *ases. 3" elems[i] = mo#e(toAdd);

Bove semantics and copy semantics are independent and in C++0) it will #e possi#le to construct o#*ects that can #e moved #ut not copied or vice1versa! 'nitially this mi&ht seem stran&e- #ut there are several cases where this is e)actly the #ehavior we want! 8or e)ample- it is ille&al to copy an ofstream #ecause the #ehavior associated with the copy is undefined ( should we duplicate the file> 'f so- where> Gr should we *ust share the file> /owever- it is perfectly le&itimate to move an ofstream from one varia#le to another- since at any instant only one ofstream varia#le will actually hold a reference to the file stream! Thus functions like this one=
ofstream Get;em$orar%=ut$ut&ile() { "3 @se the tm$nam() fun*tion from *stdio) to get the name of a 3 tem$orar% file. 5onsult a referen*e for more detail. 3" *har tm$namPuffer[7Ltm$nam]; ofstream result(tm$nam(tm$namPuffer)); return result; "" @ses move *onstru*tor, not *o$% *onstru*tor1 #

1 A@6 1

Chapter /7& C++%4

0ill #e perfectly le&al in C++0) #ecause of move constructors- thou&h the same code will not compile in current C++ #ecause ofstream has no copy constructor! ,nother e)ample of an o#*ect that has well1defined move #ehavior #ut no copy #ehavior is the C++ autoL$tr class! 'f you'll recall- assi&nin& one autoL$tr to another destructively modifies the ori&inal autoL$tr! This is e)actly the definition of move semantics! /owever- under current C++ rulesimplementin& autoL$tr is e)tremely difficult and leads to all sorts of une)pected side effects! Usin& move constructors- however- we can eliminate these pro#lems! C++0) will introduce a replacement to autoL$tr called uni[ueL$tr which- like autoL$tr- represents a smart pointer that automatically cleans up its underlyin& resource when it &oes out of scope! Unlike autoL$tr- however- uni[ueL$tr cannot #e copied or assi&ned #ut can #e moved freely! Thus code of this sort=
uni[ueL$tr int) m%<tr(ne' int); uni[ueL$tr int) other = m%<tr; "" Error1 5anAt *o$% uni[ueL$tr.

0ill not compile! /owever- #y e)plicitly indicatin& that the operation is a move- we can transfer the contents from one uni[ueL$tr to another=
uni[ueL$tr int) m%<tr(ne' int); uni[ueL$tr int) other = mo#e(m%<tr); "" 7egal; m%<tr is no' em$t%

Bove semantics and rvalue references may seem confusin& at first- #ut promise to #e a powerful and welcome addition to the C++ family! =ambda )*+ressions ast chapter- we considered the pro#lem of countin& the num#er of strings in a ve*tor whose len&ths were less than some value determined at runtime! 0e e)plored how to solve this pro#lem usin& the *ountLif al&orithm and a functor! Gur solution was as follows=
*lass 6horter;han { $ubli*4 e+$li*it 6horter;han(int ma+7ength) 4 length(ma+7ength) {# bool o$erator() (*onst string? str) *onst { return str.length() length; # $rivate4 int length; #; *onst int m%Jalue = Get(nteger(); *ountLif(m%Je*tor.begin(), m%Je*tor.end(), Ihorter%han3myKalue4);

This functor1#ased approach works correctly- #ut has a hu&e amount of #oilerplate code that o#scures the actual mechanics of the solution! 0hat we'd prefer instead is the a#ility to write code to this effect=
*onst int m%Jalue = Get(nteger() *ountLif(m%Je*tor.begin(), m%Je*tor.end(), the string is shorter than my3alue);

Usin& a new C++0) lan&ua&e feature known as lambda e4pressions Ka term those of you familiar with lan&ua&es like Scheme- B - or /askell mi&ht reco&nizeL- we can write code that very closely mirrors this structure! Gne possi#ility looks like this=

Chapter /7& C++%4


*onst int m%Jalue = Get(nteger(); *ountLif(m%Je*tor.begin(), m%Je*tor.end(), RmyKalueS3const stringP 54 L return 5.length34 2 myKalueE M);

1 A@D 1

The construct in the final line of code is a lambda e4pression- an unnamed K4anonymous6L function that e)ists only as a parameter to *ountLif! 'n this e)ample- we pass as the final parameter to *ountLif a temporary function that accepts a sin&le string parameter and returns a bool indicatin& whether or not its len&th is less than m%Jalue! The #racket synta) [m%Jalue] #efore the parameter declaration (int +) is called the capture list and indicates to C++ that the lam#da e)pression can access the value of m%Jalue in its #ody! 7ehind the scenes- C++ converts lam#da e)pressions such as the one a#ove into uni5uely1named functorsso the a#ove code is identical to the functor1#ased approach outlined a#ove! 8or those of you with e)perience in a functional pro&rammin& lan&ua&e- the e)ample outlined a#ove should strike you as an e)traordinarily powerful addition to the C++ pro&rammin& lan&ua&e! am#da e)pressions &reatly simplify many tasks and represent an entirely different way of thinkin& a#out pro&rammin&! 't will #e interestin& to see how rapidly lam#da e)pressions are adopted in professional code! Kariadic Tem+lates 'n the previous chapter we implemented a class called &un*tion that wrapped an ar#itrary unary function! Fecall that the definition of &un*tion is as follows=
template 2typename .rg%ype0 typename Beturn%ype: class ?unction { $ubli*4 "3 5onstru*tor and destru*tor. 3" tem$late t%$ename @nar%&un*tion) &un*tion(@nar%&un*tion); c&un*tion(); "3 5o$% su$$ort. 3" &un*tion(*onst &un*tion? other); &un*tion? o$erator= (*onst &un*tion? other); "3 &un*tion is a fun*tor that *alls into the stored resour*e. 3" Beturn%ype operator34 3.rg%ype #alue4 constE $rivate4 "3 ... 3" #;

0hat if we want to &eneralize &un*tion to work with functions of ar#itrary arity> That is- what if we want to create a class that encapsulates a #inary- nullary- or ternary function> Usin& standard C++- we could do this #y introducin& new classes Pinar%&un*tion- Kullar%&un*tion- and ;ernar%&un*tion that were implemented similarly to &un*tion #ut which accepted a different num#er of parameters! 8or e)ample- here's one possi#le interface for Pinar%&un*tion=

1 A@E 1

Chapter /7& C++%4

template 2typename .rg%ype10 typename .rg%ype(0 typename Beturn%ype: class Vinary?unction { $ubli*4 "3 5onstru*tor and destru*tor. 3" tem$late t%$ename Pinar%&n) Pinar%&un*tion(Pinar%&n); cPinar%&un*tion(); "3 5o$% su$$ort. 3" Pinar%&un*tion(*onst Pinar%&un*tion? other); Pinar%&un*tion? o$erator= (*onst Pinar%&un*tion? other); "3 &un*tion is a fun*tor that *alls into the stored resour*e. 3" Beturn%ype operator34 3.rg%ype1 arg(0 .rg%ype( arg(4 constE $rivate4 "3 ... 3" #;

0ritin& different class templates for functions of each arity is trou#lesome! 'f we write &un*tion1like classes for a fi)ed num#er of arities Ksay- functions #etween zero and ten ar&umentsL and then discover that we need a wrapper for a function with more ar&uments- we we'll have to write that class from scratch! Boreover- the structure of each function wrapper is almost identical! Compare the Pinar%&un*tion and &un*tion class interfaces mentioned a#ove! 'f you'll notice- the only difference #etween the classes is the num#er of template ar&uments and the num#er of ar&uments to o$erator()! 's there some way that we can use this commonality to implement a sin&le class that works with functions of ar#itrary arity> Usin& the current incarnation of C++ this is not possi#le- #ut usin& a C++0) feature called variadic templates we can do *ust this! , variadic template is a template that can accept an ar#itrary num#er of template ar&uments! These ar&uments are &rouped to&ether into ar&uments called parameter pac*s that can #e e)panded out to code for each ar&ument in the pack! 8or e)ample- the followin& class is parameterized over an ar#itrary num#er of ar&uments=
tem$late typename... .rgs) *lass ;u$le { "3 ... 3" #;

The synta) t%$ename... Args indicates that Args is a parameter pack that represents an ar#itrary num#er of ar&uments! Since Args represents a list of ar&uments rather than an ar&ument itself- it is ille&al to use Args in an e)pression #y itself! 'nstead- Args must #e used in a pattern e4pression indicatin& what operation should #e applied to each ar&ument in the pack! 8or e)ample- if we want to create a constructor for ;u$le that accepts a list of ar&uments with one ar&ument for each type in Args- we could write the followin&=
tem$late t%$ename... Args) *lass ;u$le { $ubli*4 %uple3const .rgsP ...4E #;

/ere- the synta) *onst Args? ... is a pattern e)pression indicatin& that for each ar&ument in Argsthere should #e a parameter to the constructor that's passed #y reference1to1 *onst! 8or e)ample- if we created a ;u$le int)- the constructor would #e ;u$le int)(*onst int?)- and if we create a ;u$le int, double)- it would #e ;u$le int, double)(*onst int?, *onst double?)!

Chapter /7& C++%4

1 A@< 1

et's return to the e)ample of &un*tion! Suppose that we want to convert &un*tion from encodin& a unary function to encodin& a function of ar#itrary arity! Then we could chan&e the class interface to look like this=
tem$late t%$ename Ieturn;%$e, typename... .rgument%ypes) *lass &un*tion { $ubli*4 "3 5onstru*tor and destru*tor. 3" tem$late t%$ename 5allable) &un*tion(5allable); c&un*tion(); "3 5o$% su$$ort. 3" &un*tion(*onst &un*tion? other); &un*tion? o$erator= (*onst &un*tion? other); "3 &un*tion is a fun*tor that *alls into the stored resour*e. 3" Ieturn;%$e o$erator() (.rgument%ypes... args) *onst; $rivate4 "3 ... 3" #; 8unction is now parameterized such that the first ar&ument is the return type and the remainin& ar&uments are ar&ument types! 8or e)ample- a &un*tion int, string) is a function that accepts a strin& and returns an int- while a &un*tion bool, int, int) would #e a function acceptin& two ints and returnin& a bool!

0e've *ust seen how the interface for &un*tion looks with variadi* templates- #ut what a#out the implementation> 'f you'll recall- the ori&inal implementation of &un*tion's o$erator() function looked as follows=
tem$late t%$ename Arg;%$e, t%$ename Ieturn;%$e) Ieturn;%$e &un*tion Arg;%$e, Ieturn;%$e)44o$erator()(Arg;%$e $aram) *onst { return fun*tion-)e+e*ute($aram); #

et's #e&in convertin& this to use variadic templates! The first step is to ad*ust the si&nature of the function- as shown here=
template 2typename Bet%ype0 typename... .rg%ypes: Iet;%$e &un*tion Iet;%$e, .rg%ypes...)44o$erator()(.rg%ypes... args) *onst { "3 ... 3" #

"otice that we've specified that this is a mem#er of &un*tion Iet;%$e, Arg;%$es...)! 'n the unary version of &un*tion- we implemented o$erator() #y callin& a stored function o#*ect's e)ecute mem#er function- passin& in the parameter &iven to o$erator()! 7ut how can we now call e)ecute passin& in an ar#itrary num#er of parameters> The synta) for this a&ain uses ... to tell C++ to e)pand the args parameters to the function into an actual list of parameters! This is shown here=
tem$late t%$ename Iet;%$e, t%$ename... Arg;%$es) Iet;%$e &un*tion Iet;%$e, Arg;%$es...)44o$erator()(Arg;%$es... args) *onst { return function-:e5ecute3args...4E #

1 AA0 1

Chapter /7& C++%4

$ust as usin& ... e)pands out a parameter pack into its individual parameters- usin& ... here e)pands out the varia#le1len&th ar&ument list args into each of its individual parameters! This synta) mi&ht seem a #it tricky at first- #ut is easy to pick up with practice! =ibrar/ )*tensions 'n addition to all of the lan&ua&e e)tensions mentioned in the a#ove sections- C++0) will provide a new set of li#raries that should make certain common tasks much easier to perform= )n.anced 6mart !ointers! C++0) will support a wide variety of smart pointers- such as the reference1counted sharedL$tr and the aforementioned uni[ueL$tr! @ew 6T= Containers! The current ST associative containers K ma$- set- etc!L are layered on top of #alanced #inary trees- which means that traversin& the ma$ and set always produce elements in sorted order! /owever- the sorted nature of these containers means that insertion- lookup- and deletion are all GKl& nL- where n is the size of the container! 'n C++0)- the ST will #e enhanced with unorderedLma$- unorderedLset- and multicontainer e5uivalents thereof! These containers are layered on top of hash ta#les- which have GK1L lookup and are useful when orderin& is not important! (ultit.reading 6u++ort! Tirtually all ma*or C++ pro&rams these days contain some amount of multithreadin& and concurrency- #ut the C++ lan&ua&e itself provides no support for concurrent pro&rammin&! The ne)t incarnation of C++ will support a threadin& li#rary- alon& with atomic operations- locks- and all of the #ells and whistles needed to write ro#ust multithreaded code! 4egular )*+ressions! The com#ination of C++ strings and the ST al&orithms encompasses a &ood deal of strin& processin& functionality #ut falls short of the features provided #y other lan&ua&es like $ava- Cython- and KespeciallyL Cerl! C++0) will au&ment the strin&s li#rary with full support for re&ular e)pressions- which should make strin& processin& and compiler1authorin& considera#ly easier in C++! G+graded 2functional: librar/! C++0) will e)pand on fun*tional) with a &eneric fun*tion type akin to the one descri#ed a#ove- as well as a superchar&ed bind function that can #ind ar#itrary parameters in a function with ar#itrary values! 4andom @umber eneration! C++'s only random num#er &enerator is rand- which has e)tremely low randomness Kon some implementations num#ers to&&le #etween even and oddL and is not particularly useful in statistics and machine learnin& applications! C++0)- however- will support a rich random num#er &enerator li#rary- complete with a host of random num#er &enerators and pro#a#ility distri#ution functors! (eta+rogramming Traits Classes! C++0) will provide a lar&e num#er of classes called traits classes that can help &eneric pro&rammers write optimized code! 0ant to know if a template ar&ument is an a#stract class> $ust check if isLabstra*t ;)44t%$e evaluates to trueLt%$e or falseLt%$e!

Chapter /7& C++%4 $t.er Ce/ =anguage 2eatures /ere's a small samplin& of the other up&rades you mi&ht find useful=

1 AA1 1

Gnified Initiali5ation 6/nta*= 't will #e possi#le to initialize C++ classes #y usin& the curly #race synta) Ke!&! ve*tor int) v = {8, E, C, G, H#;L Delegating Constructors= Currently- if several constructors all need to access the same code- they must call a shared mem#er function to do the work! 'n C++0)- constructors can invoke each other in initializer lists! Better )numerations= Currently- enum can only #e used to create inte&ral constants- and those constants can #e freely compared a&ainst each other! 'n C++0)- you will #e a#le to specify what type to use in an enumeration- and can disallow automatic conversions to int! Angle Brackets= 't is currently ille&al to terminate a nested template #y writin& two close #rackets consecutively- since the compiler confuses it with the stream insertion o$erator ))! This will #e fi)ed in C++0)! C"" Com+atibilit/= C++0) will formally introduce the long long type- which many current C++ compilers support- alon& with various preprocessor enhancements!

C99-* Toda/ ,lthou&h C++0) has not yet #een adopted as a standard- there are several freely1availa#le compilers that support a su#set of C++0) features! 8or e)ample- g!! versions A!A and up have support for much of C++0)and Bicrosoft Tisual Studio ;010 has a fair num#er of features implemented- includin& lam#da e)pressions and the auto keyword! 'f you want to e)perience the future of C++ today- consider downloadin& one of these compilers!

C.a+ter 1#8 1.ere to o 2rom 3ere


_________________________________________________________________________________________________________

Con&ratulationsR .ou've made it throu&h CS106 ! .ou've taken the first step on your *ourney toward a mastery of the C++ pro&rammin& lan&ua&e! This is no easy featR 'n the course of readin& throu&h this faryou now have a command of the followin& concepts= The streams li#rary- includin& how to interface with it throu&h operator overloadin&! ST containers- iterators- al&orithms- adapters- and functional pro&rammin& constructs- includin& a workin& knowled&e of how these o#*ects are put to&ether! Cointer arithmetic and how o#*ects are laid out in memory! The preprocessor and how to harness it to automatically &enerate C++ code! 3eneric pro&rammin& in C++ and *ust how powerful the C++ template system can #e! The *onst keyword and how to use it to communicate function side1effects to other pro&rammers! G#*ect layout and in1memory representation! Copy semantics and how to define implicit conversions #etween types! Gperator overloadin& and how to make a C++ class act like a primitive type! 0hat a functor is and how surprisin&ly useful and fle)i#le they are! J)ception handlin& and how to use o#*ects to automatically mana&e resources! C++0) and what C++ will look like in the future! !!! and a whole host of real1world e)amples of each of these techni5ues!

2espite all of the material we've covered here- there is much more to learn in the world of C++ and your *ourney has *ust #e&un! ' feel that it is a fittin& conclusion to this course reader to direct you toward other C++ resources that will prove invalua#le alon& your *ourney into the wondrous realm of this lan&ua&e! 'n particular- there are several e)cellent C++ resources ' would #e remiss to omit= E$$ective C++- -ore E$$ective C++- and E$$ective ,TL #y Scott Beyers! Cickin& up and readin& this trio of #ooks is perhaps the #est thin& you can do for yourself as a C++ pro&rammer! The #ooks in the E$$ective C++ series will help you transition from a solid C++ pro&rammer into an e)cellent C++ pro&rammer and are widely re&arded as amon& the #est C++ #ooks on the market! 0hat separates the E$$ective C++ series from most other C++ #ooks is that E$$ective C++ focuses almost e)clusively on correct usa&e of core C++ lan&ua&e features and how to avoid common pitfalls! 'f you plan on usin& C++ in the professional world- you should own copies of this #ook!

1 AAA 1

Chapter /?& 'here to 0o From +ere E4ceptional C++ #y /er# Sutter! This #ook is an invalua#le tool in any C++ pro&rammer's arsenal! The #ook is lar&ely or&anized as a set of puzzles that &ive you a chance to think a#out the #est way to solve a pro#lem and what C++ issues you'll encounter in the process! ,lon& with E$$ective C++- E4ceptional C++ is one of the most hi&hly1recommended C++ #ooks out there! /er# Sutter's personal we#site is also an e)cellent resource for all your C++ needs!

The #esign and Evolution o$ C++ #y 7*arne Stroustrup! This #ookaffectionately known to hardcore C++ pro&rammers as #OE- is a &limpse into 7*arne Stroustrup's thou&ht processes as he went a#out desi&nin& C++! 2fJ is not a pro&rammin& &uide- #ut rather a history of the evolution of C++ from the small lan&ua&e C with Classes into the modern lan&ua&e we know and love today! 2fJ was written #efore C++ had #een 'SG standardized and even predates the ST - meanin& that it can offer a new perspective on some of the lan&ua&e features and li#raries you may take for &ranted! 'f you want an interestin& &limpse into the mind of the man #ehind C++- this is the #ook for you!

-odern C++ #esign& 0eneric Programming and #esign Patterns Applied #y ,ndrei ,le)andrescu! Considered the seminal work in modern C++ pro&rammin&- this #ook is an e)cellent introduction into an entirely new way of thinkin& in C++! ,le)andrescu takes many advanced lan&ua&e features like templates and multiple inheritance- then shows how to harness them to achieve syner&istic effects that are far more powerful than any of the individual features used! ,s an e)ample- the first chapter shows how to write a sin&le smart pointer class that is capa#le of storin& any type of value- performin& any sort of resource mana&ement- and havin& any copy #ehavior that the client desires! The #ook is very lan&ua&e1intensive and re5uires you to have a &rasp of C++ sli&htly #eyond the scope of this reader- #ut is a most wonderful te)t for all who are interested!

Chapter /?& 'here to 0o From +ere 2inal T.oug.ts

1 AA? 1

't's #een 5uite a trip since we first started with the streams li#rary! .ou now know how to pro&ram with the ST - write well1#ehaved C++ o#*ects- and even how to use functional pro&rammin& constructs! 7ut despite the immense amount of material we've covered- we have #arely scratched the surface of C++! There are volumes of articles and #ooks out there that cover all sorts of amazin& C++ tips and tricks- and #y takin& the initiative and e)plorin& what's out there you can hone your C++ skills until pro#lem solvin& in C++ transforms from 4how do ' solve this pro#lem>6 to 4which of these many options is #est for solvin& this pro#lem>6 C++ is an amazin& lan&ua&e! 't has some of the most e)pressive synta) of any modern pro&rammin& lan&ua&e- and affords an enormous latitude in pro&rammin& styles! Gf course- it has its flaws- as critics are ea&er to point out- #ut despite the advent of more modern lan&ua&es like $ava and Cython C++ still occupies a prime position in the software world! ' hope that you've en*oyed readin& this course reader as much as ' en*oyed writin& it! 'f you have any comments- su&&estions- or criticisms- feel free to email me at htiek9cs!stanford!edu! ike the C++ lan&ua&e- CS106 and this course reader are constantly evolvin&- and if there's anythin& ' can do to make the class more en*oya#le- #e sure to let me knowR /ave fun with C++- and ' wish you the #est of luck wherever it takes youR 1 Keith

!art 2our
$b%ect&$riented !rogramming

C.a+ter 1N8 Introduction to In.eritance


_________________________________________________________________________________________________________

't's impossi#le to learn C++ or any other o#*ect1oriented lan&ua&e without encounterin& inheritance- a mechanism that lets different classes share implementation and interface desi&n! /owever- inheritance has evolved &reatly since it was first introduced to C++- and conse5uently C++ supports several different inheritance schemes! This chapter introduces and motivates inheritance- then discusses how inheritance interacts with other lan&ua&e features! In.eritance of Im+lementation and Interface C++ started off as a lan&ua&e called 4C with Classes-6 so named #ecause it was essentially the C pro&rammin& lan&ua&e with support for classes and o#*ect1oriented pro&rammin&! C++ is the more modern incarnation of C with Classes- so most K#ut not allL of the features of C with Classes also appear in C++! The inheritance introduced in C with Classes allows you to define new classes in terms of older ones! 8or e)ample- suppose you are usin& a third1party li#rary that e)ports a <rinter class- as shown #elow=
*lass <rinter { $ubli*4 "3 5onstru*tor, destru*tor, et*. 3" void set&ont(*onst string? fontKame, int siUe); void set5olor(*onst string? *olor); void $rint9o*ument(*onst string? do*ument); $rivate4 "3 (m$lementation details 3" #;

This <rinter class e)ports several formattin& functions- plus $rint9o*ument- which accepts a strin& of the document to print! et's assume that $rint9o*ument is implemented synchronously ( that is$rint9o*ument will not return until the document has finished printin&! 'n some cases this #ehavior is fine- #ut in others it's simply not accepta#le! 8or e)ample- suppose you're writin& data#ase software for a lar&e li#rary and want to &ive users the option to print out call num#ers! Chances are that people usin& your software will print call num#ers for multiple #ooks and will #e irritated if they have to sit and wait for their documents to finish printin& #efore continuin& their search! To address this pro#lem- you decide to add a new feature to the printer that lets the users en5ueue several documents and print them in a sin&le #atch *o#! That way- users searchin& for #ooks can en5ueue call num#ers without lon& pauses- then print them all in one operation! /owever- you don't want to force users to 5ueue up documents and then do a #atch print *o# at the end ( after all- may#e they're *ust lookin& for one #ook ( so you want to retain all of the ori&inal features of the <rinter class! /ow can you ele&antly solve this pro#lem in software> et's consider the a#ove pro#lem from a pro&rammin& perspective! The important points are= 0e are provided the <rinter class from an e)ternal source- so we cannot modify the <rinter interface! 0e want to preserve all of the e)istin& functionality from the <rinter class! 0e want to e)tend the <rinter class to include e)tra functionality!

1 A?0 1

Chapter /=& Introduction to Inheritance

This is an ideal spot to use inheritance- a means for definin& a new class in terms of an older one! 0e have an e)istin& class that contains most of our needed functionality- #ut we'd like to add some e)tra features! et's define a Pat*h<rinter class that supports two new functions- en[ueue9o*ument and $rintAll9o*uments- on top of all of the re&ular <rinter functionality! 'n C++- we write this as
*lass Pat*h<rinter" public 1rinter "" (nherit from <rinter { $ubli*4 void en[ueue9o*ument(*onst string? do*ument); void $rintAll9o*uments(); $rivate4 [ueue string) do*uments; "" 9o*ument [ueue #;

/ere- the class declaration *lass Pat*h<rinter4 $ubli* <rinter indicates that the new class Pat*h<rinter inherits the functionality of the <rinter class! ,lthou&h we haven't e)plicitly provided the $rint9o*ument or set&ont functions- since those functions are defined in <rinter- they are also part of Pat*h<rinter! 8or e)ample=
Pat*h<rinter m%<rinter; m%<rinter.setHolor3FBedF4E m%<rinter.print=ocument3F%his is a document!F4E m%<rinter.en&ueue=ocument3F1rint this one later.F4E m%<rinter.print.ll=ocuments34E "" "" "" "" (nherited from <rinter 6ame 9efined in Pat*h<rinter 6ame

0hile the Pat*h<rinter can do everythin& that a <rinter can do- the converse is not true ( a <rinter cannot call en[ueue9o*ument or $rintAll9o*uments- since we did not modify the <rinter class interface! 'n the a#ove setup- <rinter is called a base class of Pat*h<rinter- which is a derived class! 'n C++ *ar&on- the relationship #etween a derived class and its #ase class is the is"a relationship! That is- a Pat*h<rinter is"a <rinter #ecause everythin& the <rinter can do- the Pat*h<rinter can do as well! The converse is not true- thou&h- since a <rinter is not necessarily a Pat*h<rinter! 7ecause Pat*h<rinter is"a <rinter- anywhere that a <rinter is e)pected we can instead provide a Pat*h<rinter! 8or e)ample- suppose we have a function that accepts a <rinter o#*ect- perhaps to confi&ure its font renderin&- as shown here=
void (nitialiUe<rinter(<rinter? $);

Then the followin& code is perfectly le&al=


Pat*h<rinter bat*h; (nitialiUe<rinter(batch);

,lthou&h (nitialiUe<rinter e)pects an ar&ument of type <rinter?- we can instead provide it a Pat*h<rinter! This operations is well1defined and perfectly safe #ecause the Pat*h<rinter contains all of the functionality of a re&ular <rinter! 'f we temporarily for&et a#out all of the e)tra functionality provided #y the Pat*h<rinter class- we still have a &ood old1fashioned <rinter! 0hen workin& with inheritance- you can think of the types of ar&uments to functions as specifyin& the minimum re5uirements for the parameter! , function acceptin& a <rinter? or a *onst <rinter? can take in a o#*ect of any typeprovided of course that it ultimately derives from <rinter!

Chapter /=& Introduction to Inheritance

1 A?1 1

1 A?; 1

Chapter /=& Introduction to Inheritance

"ote that it is completely le&al to have several classes inherit from a sin&le #ase class! Thus- if we wanted to develop another printer that supported &raphics printin& in addition to te)t- we could write the followin& class definition=
*lass Gra$hi*s<rinter4 public 1rinter { $ubli*4 "3 5onstru*tor, destru*tor, et*. 3" void $rint<i*ture(*onst <i*ture? $i*ture); "" &or some <i*ture *lass $rivate4 "3 (m$lementation details 3" #;

"ow- Gra$hi*s<rinter can do everythin& a re&ular <rinter can do- #ut can also print <i*ture o#*ects! ,&ain- Gra$hi*s<rinter is"a <rinter- #ut not vice1versa! Similarly- Gra$hi*s<rinter is not a Pat*h<rinter! ,lthou&h they are #oth derived classes of <rinter- they have nothin& else in common! 't sometimes help to visualize the inheritance relations #etween classes as a tree! 0e adopt the convention that if one class derives from another- the first class is represented as a child of the second! 0e also la#el all ed&es in the tree with arrows pointin& from derived classes to #ase classes! 8or e)ample<rinter- Pat*h<rinter- and Gra$hi*s<rinter are all related as follows=
1rinter

Vatch1rinter

Graphics1rinter

4untime Costs of Basic In.eritance The inheritance scheme outlined a#ove incurs no runtime penalties! inheritance will #e *ust as fast as pro&rams not usin& inheritance! Cro&rams usin& this type of

'n memory- a derived class is simply a #ase class o#*ect with its e)tra data mem#ers tacked on the end! 8or e)ample- suppose you have the followin& classes=
*lass Pase5lass { $rivate4 int baseR, baseS; #; *lass 9erived5lass" public VaseHlass { $rivate4 int derR, derS; #;

Then- in memory- a 9erived5lass o#*ect looks like this=

Chapter /=& Introduction to Inheritance


Address 8000 800G 800F 808E baseR baseS derR derS

1 A?@ 1

2- VaseHlass members 2- =eri#edHlass)speci*ic members

"otice that the first ei&ht #ytes of this o#*ect are precisely the data mem#ers of a Pase5lass o#*ect! This is in part the reason that you can treat instances of a derived class as instances of a #ase class! This in1 memory representation of inheritance is e)tremely efficient and is one of the reasons that C++ was so popular in its infancy! Bost competin& o#*ect1oriented lan&ua&es represented o#*ects with considera#ly more complicated structures that re5uired comple) pointer lookups- so inheritance in those lan&ua&es incurred a steep runtime penalty! C++- on the other hand- supported this simple form of inheritance with zero overhead! In.eritance of Interface The inheritance pattern outlined a#ove uses inheritance to add e4tensions to e)istin& classes! This is undou#tedly useful- #ut does not arise fre5uently in practice! , different version of inheritance- called inheritance o$ inter$ace- is e)traordinarily useful in modern pro&rammin&! et's return to the <rinter class! <rinter e)ports a $rint9o*ument mem#er function that accepts a string parameter- then sends the strin& to the printer! Gne of our other derived classesGra$hi*s<rinter- has a $rint<i*ture mem#er function that accepts some sort of <i*ture o#*ect- then sends the picture to the printer! 0hat if we want to print a document containin& a mi) of te)t and pictures ( for e)ample- this course reader> 0e'd then need to introduce yet another su#class of <rinter- perhaps a :i+ed;e+t<rinter- that supports a $rint:i+ed;e+t mem#er function that prints a com#ination of te)t and ima&es! 0hile we could continue to use the style of inheritance introduced a#ove- it will 5uickly spiral out of control for several reasons! 8irst- each printer can only print out one type of document! That is- a :i+ed;e+t<rinter cannot print out pictures- nor a Gra$hi*s<rinter a mi)ed1te)t document! 0e could eliminate this pro#lem #y writin& a sin&le :i+ed;e+tAndGra$hi*s<rinter class- #ut this too has its pro#lems if we then introduce another type of o#*ect to print Ksay- a hi&h1resolution photoL that re5uired its own special printin& code! This leads to the second pro#lem- a lack of e)tensi#ility! 8or any new type of o#*ect we want to print- we need to introduce another mem#er function or class capa#le of handlin& that o#*ect! 'n our case this is inconvenient and does not scale well! 0e need to pick another plan of attack! The pro#lem is that everythin& that mi&ht &et sent to the printer re5uires sli&htly different lo&ic to print out! Te)t documents need to apply fonts and formattin& transformations- &raphics documents need to convert from some application1specific format into somethin& reada#le #y the printer- and mi)ed1te)t documents need to arran&e their te)t and ima&es into an appropriate layout #efore processin& each piece individually! 7ut each type of document has one piece of functionality in common! Iost printers are pro/rammed to accept as inp#t a /rid o* dots representin/ the doc#ment to print. That is, whether yo#.re printin/ te4t or a three)dimensional pie chart, the inp#t to the printer is a /rid o* pi4els representin/ the dots ma0in/ #p the ima/e. + te4t doc#ment mi/ht end #p prod#cin/ di**erent pi4els than a hi/h)resol#tion photo, b#t they both end #p as pi4els at some point. Provided that we can trans*orm an obAect in memory into a mess o* pi4els, we can send it to the printer. "onsider the *ollowin/ class de*inition *or a Generi*Pat*h<rinter obAectF

1 A?A 1
*lass Generi*Pat*h<rinter { $ubli*4 "3 5onstru*tor, destru*tor, et*. 3" void en[ueue9o*ument( /G $hat goes here! G/ ); void $rintAll9o*uments(); $rivate4 "3 (m$lementation details 3" #;

Chapter /=& Introduction to Inheritance

This Generi*Pat*h<rinter o#*ect e)ports an en[ueue9o*ument function that stores an ar#itrary document in a print 5ueue that can then #e printed #y callin& $rintAll9o*uments! There is one ma*or 5uestion- thou&h= what should the parameter type #e> 0e can print any type of document we can think ofprovided that we can convert it into a &rid of pi)els! 0e mi&ht #e tempted to accept a &rid of pi)els as a parameter! This- however- has several draw#acks! 8irst- pi)el &rids take up a hu&e amount of memory! Color printers usually store color information as 5uadruples of the cyan- ma&enta- yellow- and #lack KC.BKL color components- so a sin&le pi)el is usually a four1#yte value! 'f you have a ;00 2C' printer and want to print to an E!? ) 11W pa&e- you'd need to store around D?k#! That's a lot of memory- and if you wanted to en5ueue a lar&e num#er of documents this approach mi&ht strain or e)haust system resources! Clus- we don't actually need the pi)els until we #e&in printin&- and even then we only need pi)el information for one document at a time! Second- what if later in desi&n we realize that we need e)tra information a#out the print *o#> 8or e)ample- suppose we want to implement a printin& priority system where more ur&ent documents print #efore less important ones! 'n this case- we'd need to add an e)tra parameter to en[ueue9o*ument representin& that priority and all e)istin& code usin& en[ueue9o*ument would stop workin&! 8inally- this approach e)poses too much of the inner workin&s of Generi*Pat*h<rinter to the client! 7y treatin& documents as masses of pi)els instead of documents- the Generi*Pat*h<rinter violates some of the fundamental rules of data a#straction! et's review these pro#lems= The a#ove approach is needlessly memory1intensive #y caterin& to the lowest common denominator of all possi#le printa#le documents! The approach limits later e)tensions #y fi)in& the parameter as an infle)i#le pi)el array! The Generi*Pat*h<rinter should work on documents- not pi)els!

's there a lan&ua&e feature that would let us solve all of these pro#lems> The answer is yes! 0hat if we simply create an o#*ect that looks like this=
*lass 9o*ument { $ubli*4 "3 5onstru*tor, destru*tor, et*. 3" grid $i+el;) *onvert;o<i+elArra%() *onst; "" &or some stru*t $i+el; int get<riorit%() *onst; $rivate4 "3 (m$lementation details 3" #;

This 9o*ument class e)ports two functions ( *onvert;o<i+elArra%()- which converts the document from its current format into a grid $i+el;) of the pi)els in the ima&e- and get<riorit%()- which returns the relative priority of the document!

Chapter /=& Introduction to Inheritance

1 A?? 1

1 A?6 1

Chapter /=& Introduction to Inheritance

0e can now have the en[ueue9o*ument function from Generi*Pat*h<rinter accept a 9o*ument as a parameter! That way- when the Generi*Pat*h<rinter needs to &et an array of pi)els- it can simply call *onvert;o<i+elArra% on any stored 9o*ument! Similarly- if the Generi*Pat*h<rinter decides to implement a priority system- it can use the information provided #y the 9o*ument's get<riorit%() function! Boreover- if later on durin& implementation we realize that Generi*Pat*h<rinter needs access to additional information- we can simply add e)tra mem#er functions to the 9o*ument class! 0hile this still re5uires us to rewrite code to add these mem#er functions- the actual calls to en[ueue9o*ument will still work correctly- and the only people who need to modify any code is the 9o*ument class implementer- not the 9o*ument class clients! 0hile this solution mi&ht seem ele&ant- it still has a ma*or pro#lem ( how can we write a 9o*ument class that encompasses all of the possi#le documents we can try to print> The answer is simple= we can't! Usin& the lan&ua&e features we've covered so far- it simply isn't possi#le to solve this pro#lem! Consider for a minute what form our pro#lem looks like! 0e need to provide a 9o*ument o#*ect that represents a printa#le document- #ut we cannot write a sin&le um#rella class representin& every conceiva#le document! 'nstead of creatin& a sin&le 9o*ument class- what if we could create several di$$erent 9o*ument classes- each of which provided a workin& implementation of the *onvert;o<i+elArra% and get9o*umentKame functions> That is- we mi&ht have a ;e+t9o*ument class that stores a string and whose *onvert;o<i+elArra% converts the strin& into a &rid of pi)els representin& that strin&! 0e could also have a Gra$hi*s9o*ument o#*ect with mem#er functions like add5ir*le or add(mage whose *onvert;o<i+elArra% function &enerates a &raphical representation of the stored ima&e! 'n other words- we want to make the 9o*ument class represent an inter$ace rather than an implementation! 9o*ument should simply outline what mem#er functions are common to other classes like Gra$hi*s9o*ument or ;e+t9o*ument without specifyin& how those functions should work! 'n C++ code- this means that we will rewrite the 9o*ument class to look like this=
*lass 9o*ument { $ubli*4 "3 5onstru*tor, destru*tor, et*. 3" #irtual int3 *onvert;o<i+elArra%() *onst O 0; #irtual string get9o*umentKame() *onst O 0; $rivate4 "3 (m$lementation details 3" #;

'f you'll notice- we ta&&ed #oth of the mem#er functions with the virtual keyword- and put an = 0 after each function declaration! 0hat does this stran&e synta) mean> The = 0 synta) is an odd #it of C++ synta) that says 4this function does not actually e)ist!6 'n other words- we've prototyped a function that we have no intention of ever writin&! 0hy would we ever want to do this> The reason is simple! 7ecause we've prototyped the function- other pieces of C++ code know what the parameter and return types are for the *onvert;o<i+elArra% and get9o*umentKame functions! /owever- since there is no meanin&ful implementation for either of these functions- we add the = 0 to tell C++ not to e)pect one! To understand the virtual keyword- consider this ;e+t9o*ument class outlined #elow=

Chapter /=& Introduction to Inheritance


*lass ;e+t9o*ument4 public =ocument "" (nherit from 9o*ument { $ubli*4 "3 5onstru*tor, destru*tor, et*. 3" #irtual grid2pi5el%: con#ert%o1i5el.rray34 constE "" 0as an im$lementation #irtual int get1riority34 constE "" 0as an a*tual im$lementation void set;e+t(*onst string? te+t); "" ;e+t-s$e*ifi* formatting fun*tions void set&ont(*onst string? font); void set6iUe(int siUe); $rivate4 "3 (m$lementation details 3" #;

1 A?D 1

This ;e+t9o*ument class inherits from 9o*ument- and althou&h 9o*ument has a declaration of the *onvert;o<i+elArra% and get<riorit% functions- ;e+t9o*ument has specified that it too contains these functions! They are marked virtual- as in the 9o*ument class- #ut unlike 9o*ument's versions of these functions the ;e+t9o*ument functions do not have the = 0 notation after them! This indicates that the functions actually e)ist and do have implementations! 0e won't cover how these functions are implemented since it's irrelevant to our discussion- #ut #ecause they have actual implementations code like this is perfectly le&al=
;e+t9o*ument m%9o*ument; grid $i+el;) arra% = my=ocument.con#ert%o1i5el.rray34E

0e've covered the = 0 notation- #ut what does the virtual keyword mean> To understand how virtual works- consider the followin& code snippet=
;e+t9o*ument3 m%9o*ument = new %e5t=ocument; grid $i+el;) arra% = m%9o*ument-)*onvert;o<i+elArra%();

This code should not #e at all surprisin& ( we've *ust rewritten the a#ove code usin& a pointer to a ;e+t9o*ument rather than a stack1#ased ;e+t9o*ument! /owever- consider this code snippet #elow=
=ocumentG m%9o*ument = ne' ;e+t9o*ument; "" Kote4 $ointer is a 9o*ument 3 grid $i+el;) arra% = my=ocument-:con#ert%o1i5el.rray34;

This code looks similar to the a#ove code #ut represents a fundamentally different operation! 'n the first line- we allocate a new ;e+t9o*ument o#*ect- #ut store it in a pointer of type 9o*ument 3! 'nitially- this mi&ht seem nonsensical ( pointers of type 9o*ument 3 should only #e a#le to point to o#*ects of type 9o*ument! /owever- #ecause ;e+t9o*ument is a derived class of 9o*ument- 6ext8ocument is" a 8ocument! The is"a relation applies literally here ( since ;e+t9o*ument is"a 9o*ument- we can point to o#*ects of type ;e+t9o*ument usin& pointers of type 9o*ument 3! Jven if we can point to o#*ects of type ;e+t9o*ument with o#*ects of type 9o*ument 3- why is the line m%9o*ument-)*onvert;o<i+elArra%() le&al> ,s mentioned earlier- the 9o*ument class definition says that 9o*ument does not have an implementation of *onvert;o<i+elArra%- so it seems like this code should not compile! This is where the virtual keyword comes in! Since we marked *onvert;o<i+elArra% virtual- when we call the *onvert;o<i+elArra% function throu&h a 9o*ument 3 o#*ect- C++ will call the function named *onvert;o<i+elArra% for the class that's actually being pointed at- not the *onvert;o<i+elArra% function defined for o#*ects of the type of the pointer! 'n this case- since our 9o*ument 3 is actually pointin& at a ;e+t9o*ument- the call to *onvert;o<i+elArra% will call the ;e+t9o*ument's version of *onvert;o<i+elArra%!

1 A?E 1

Chapter /=& Introduction to Inheritance

Chapter /=& Introduction to Inheritance

1 A?< 1

The a#ove approach to the pro#lem is known as polymorphism! 0e define a #ase class Kin this case 9o*umentL that e)ports several functions marked virtual! 'n our pro&ram- we pass around pointers to o#*ects of this #ase class- which may in fact #e pointin& to a #ase class o#*ect or to some derived class! 0henever we make mem#er function calls to the virtual functions of the #ase class- C++ fi&ures out at runtime what type of o#*ect is #ein& pointed at and calls its implementation of the virtual function! et's return to our Generi*Pat*h<rinter class- which now in its final form looks somethin& like this=
*lass Generi*Pat*h<rinter { $ubli*4 "3 5onstru*tor, destru*tor, et*. 3" void en[ueue9o*ument(=ocumentG do*); void $rintAll9o*uments(); $rivate4 &ueue2=ocument G: documentsE #;

Gur en[ueue9o*ument function now accepts a 9o*ument 3- and its private data mem#ers include an ST [ueue of 9o*ument 3s! 0e can now implement en[ueue9o*ument and $rintAll9o*uments usin& code like this=
#oid GenericVatch1rinter""en&ueue=ocument3=ocumentG doc4 L documents.push3doc4E "" Ie*all 6;7 [ueue uses $ush instead of en[ueue M #oid GenericVatch1rinter""print.ll=ocuments34 L /G 1rint all en&ueued documents G/ while3!documents.empty344 L =ocumentG ne5t=ocument O documents.front34E documents.pop34E "" Ie*all 6;7 [ueue re[uires e+$li*it $o$ o$eration send%o1rinter3ne5t=ocument-:con#ert%o1i5el.rray344E delete ne5t=ocumentE "" Assume it 'as allo*ated 'ith ne'

M M

The en[ueue9o*ument function accepts a 9o*ument 3 and en5ueues it in the document 5ueue- and the $rintAll9o*uments function continuously de5ueues documents- converts them to pi)el arrays- then sends them to the printer! 7ut while this a#ove code mi&ht seem simple- it's actually workin& some wonders #ehind the scenes! "otice that when we call ne+t9o*ument-)*onvert;o<i+elArra%()- the o#*ect pointed at #y ne+t9o*ument could #e of any type derived from 9o*ument! That is- the a#ove code will work whether we've en5ueued ;e+t9o*uments- Gra$hi*s9o*uments- or even :i+ed;e+t9o*uments! Boreover- the Generi*Pat*h<rinter class does not even need to know of the e)istence of these types of documentsQ as lon& as Generi*Pat*h<rinter knows the &eneric 9o*ument interface- C++ can determine which functions to call! This is the main stren&th of inheritance ( we can write code that works with o#*ects of ar#itrary types #y identifyin& the common functionality across those types and writin& code solely in terms of these operations!

1 A60 1 Kirtual 2unctionsI !ure Kirtual 2unctionsI and Abstract Classes

Chapter /=& Introduction to Inheritance

'n the a#ove e)ample with the 9o*ument class- we defined 9o*ument as
*lass 9o*ument { $ubli*4 "3 5onstru*tor, destru*tor, et*. 3" virtual grid $i+el;) *onvert;o<i+elArra%() *onst = 0; virtual string get9o*umentKame() *onst = 0; $rivate4 "3 (m$lementation details 3" #;

/ere- all of the 9o*ument mem#er functions are marked virtual and have the = 0 synta) to indicate that the functions are not actually defined! 8unctions marked virtual with = 0 are called pure virtual $unctions and represent functions that e)ist solely to define how other pieces of C++ code should interact with derived classes!P Classes that contain pure virtual functions are called abstract classes! 7ecause a#stract classes contain code for which there is no implementation- it is ille&al to directly instantiate a#stract classes! 'n the case of our document e)ample- this means that #oth of the followin& are ille&al=
9o*ument m%9o*ument; "" Error1 9o*ument3 m%9o*ument = ne' 9o*ument; "" Error1

Gf course- it's still le&al to declare 9o*ument 3 varia#les- since those are pointers to a#stract classes rather than a#stract classes themselves! , derived class whose #ase class is a#stract may or may not implement all of the pure virtual functions defined in the #ase class! 'f the derived class does implement each function- then the derived class is non1 a#stract Kunless- of course- it introduces its own pure virtual functionsL! Gtherwise- if there is at least one pure virtual function declared in the #ase class and not defined in the derived class- the derived class itself will #e an a#stract class! There is no re5uirement that functions marked virtual #e pure virtual functions! That is- you can provide virtual functions that have implementations! 8or e)ample- consider the followin& class representin& a roller1#lader=
*lass IollerPlader { $ubli*4 "3 5onstru*tor, destru*tor, et*. 3" #irtual #oid slow=own34E "" Jirtual, not $ure virtual $rivate4 "3 (m$lementation details 3" #; P Those of you familiar with inheritance in other lan&ua&es like $ava mi&ht wonder why C++ uses the awkward = 0 synta) instead of a clearer keyword like abstra*t or $ure! The reason was mostly political! 7*arne Stroustrup introduced pure virtual functions to the C++ lan&ua&e several weeks #efore the planned release of the ne)t set of revisions to C++! ,ddin& a new keyword would have delayed the ne)t lan&ua&e release- so to ensure that C++ had support for pure virtual functions- he chose the = 0 synta)!

Chapter /=& Introduction to Inheritance


void IollerPlader44slo'9o'n() "" (m$lementation doesnAt have virtual Be%'ord { a$$l%PraBes(); #

1 A61 1

/ere- slo'9o'n is implemented as a virtual function that is not pure virtual! 'n the implementation of slo'9o'n- you do not repeat the virtual keyword- and for all intents and purposes treat slo'9o'n as a re&ular C++ function! "ow- suppose we write a (ne+$erien*edIollerPlader class- as shown here=
*lass (ne+$erien*edIollerPlader" public BollerVlader { $ubli*4 "3 5onstru*tor, destru*tor, et*. 3" #irtual #oid slow=own34E $rivate4 "3 (m$lementation details 3" #; void (ne+$erien*edIollerPlader44slo'9o'n() { fall9o'n(); #

This (ne+$erien*edIollerPlader class provides its own implementation of slo'9o'n that calls some fall9o'n function!P "ow- consider the followin& code snippet=
IollerPlader3 blader = ne' IollerPlader; blader-:slow=own34E IollerPlader3 bladerE = ne' (ne+$erien*edIollerPlader; blader(-:slow=own34E

'n #oth cases- we call the slo'9o'n function throu&h a pointer of type IollerPlader 3- so C++ will call the version of slo'9o'n for the class that's actually pointed at! 'n the first case- this will call the IollerPlader's version of slo'9o'n- which calls a$$l%PraBes! 'n the second- since bladerE points to an (ne+$erien*edIollerPlader- the slo'9o'n call will call (ne+$erien*edIollerPlader's slo'9o'n function- which then calls fall9o'n! 'n &eneral- when callin& a virtual function- C++ will invoke the version of the function that corresponds to the most derived implementation availa#le in the o#*ect #ein& pointed at! 7ecause the (ne+$erien*edIollerPlader implementation of slo'9o'n replaces the #ase class version- (ne+$erien*edIollerPlader's implementation slo'9o'n is said to override IollerPlader's! 0hen inheritin& from non1a#stract classes that contain virtual functions- there is no re5uirement to provide your own implementation of the virtual functions! 8or e)ample- a 6tuntIollerPlader mi&ht #e a#le to do tricks a re&ular IollerPlader can't- #ut still slows down the same way! 'n code we could write this as
*lass 6tuntIollerPlader" public BollerVlader { $ubli*4 "3 Kote4 no mention of slow=own 3" void ba*Bfli$(); void tri$leA+el(); P Gf course- this is not #ased on personal e)perience!

1 A6; 1
#;

Chapter /=& Introduction to Inheritance

'f we then were to write code that used 6tuntIollerPlader- callin& slo'9o'n would invoke IollerPlader's version of slo'9o'n since it is the most derived implementation of slo'9o'n availa#le to 6tuntIollerPlader! 8or e)ample=
IollerPlader3 blader = ne' 6tuntIollerPlader; blader-:slow=own34; "" 5alls IollerPlader44slo'9o'n

Similarly- if we were to create a class ;erribl%(ne+$erien*edIollerPlader that e)ports a $ani* function #ut no slo'9o'n function- as shown here=
*lass ;erribl%(ne+$erien*edIollerPlader" public Ine5periencedBollerVlader { $ubli*4 "3 Kote4 no referen*e to slow=own 3" void $ani*(); #;

Then the followin& code will invoke (ne+$erien*edIollerPlader44slo'9o'n- causin& the roller #lader to fall down=
IollerPlader3 blader = ne' ;erribl%(ne+$erien*edIollerPlader; blader-:slow=own34;

'n this last e)ample we wrote a class that derived from a class which itself was a derived class! This is perfectly le&al and arises commonly in pro&rammin& practice! A 1ord of 1arning Consider the followin& two classes=
*lass KotJirtual { $ubli*4 #oid not.Kirtual?unction34E #; *lass KotJirtual9erived4 public @otKirtual { $ubli*4 #oid not.Kirtual?unction34E #;

/ere- the #ase class KotJirtual e)ports a function called notAJirtual&un*tion and its derived classKotJirtual9erived- also provides a notAJirtual&un*tion function! ,lthou&h these functions have the same name- since notAJirtual&un*tion is not marked virtual- the derived class version does not replace the #ase class version! Consider this code snippet=
KotJirtual3 nv = ne' KotJirtual9erived; n#-:not.Kirtual?unction34E

/ere- since KotJirtual9erived is1a KotJirtual- the a#ove code will compile! /owever- since notAJirtual&un*tion is Kas its name su&&estsL not a virtual function- the a#ove code will call the KotJirtual version of notAJirtual&un*tion- not KotJirtual9erived's notAJirtual&un*tion!

Chapter /=& Introduction to Inheritance

1 A6@ 1

1 A6A 1

Chapter /=& Introduction to Inheritance

'f you want to let derived classes override functions in a #ase class- you must mark the #ase class's function virtual! Gtherwise- C++ won't treat the function call virtually and will always call the version of the function associated with the type of the pointer! 8or e)ample=
KotJirtual3 nv = ne' KotJirtual9erived; n#-:not.Kirtual?unction34E "" 5alls @otKirtual44notAJirtual&un*tion() KotJirtual9erived 3nvE = ne' KotJirtual9erived; n#(-:not.Kirtual?unction34E "" 5alls @otKirtual=eri#ed44notAJirtual&un*tion();

'n &eneral- it is considered #ad pro&rammin& practice to have a derived class implement a mem#er function with the same name as a non1virtual function in its #ase class! 2oin& so leads to the sorts of odd #ehavior shown a#ove and is an easy source of errors! T.e protected Access 6+ecifier et's return to the 9o*ument class from earlier in the chapter! Suppose that while desi&nin& some of the 9o*ument su#classes- we note that every sin&le su#class ends up havin& a 'idth and height field! To minimize code duplication- we decide to move the 'idth and height fields from the derived classes into the 9o*ument #ase class! Since we don't want 9o*ument class clients directly accessin& these fields- we decide to mark them $rivate- as shown here=
*lass 9o*ument { $ubli*4 "3 5onstru*tor, destru*tor, et*. 3" virtual grid $i+el;) *onvert;o<i+elArra%() *onst = 0; virtual string get9o*umentKame() *onst = 0; $rivate4 int width0 height; "" 2arning4 slight $roblem here #;

/owever- #y movin& 'idth and height into the 9o*ument #ase class- we've accidentally introduced a pro#lem into our code! Since 'idth and height are $rivate- even thou&h ;e+t9o*ument and the other su#classes inherit from 9o*ument- the su#classes will not #e a#le to access the 'idth and height fields! 0e want the 'idth and height fields to #e accessi#le only to the derived classes- #ut not to the outside world! Usin& only the C++ we've covered up to this point- this is impossi#le! /owever- there is a third access specifier #eyond $ubli* and $rivate called protected that does e)actly what we want! 2ata mem#ers and functions marked $rote*ted- like $rivate data mem#ers- cannot #e accessed #y class clients! /owever- unlike $rivate varia#les- $rote*ted functions and data mem#ers are accessi#le #y derived classes!
$rote*ted is a useful access specifier that in certain circumstances can make your code 5uite ele&ant! /owever- you should #e very careful when &rantin& derived classes $rote*ted access to data mem#ers! ike $ubli* data mem#ers- usin& $rote*ted data mem#ers locks your classes into a sin&le

implementation and can make code chan&es down the line difficult to impossi#le! Bake sure that markin& a data mem#er $rote*ted is truly the ri&ht choice #efore proceedin&! /owever- markin& member $unctions $rote*ted is a common pro&rammin& techni5ue that lets you e)port mem#er functions only usa#le #y derived classes! 0e will see an e)ample of $rote*ted mem#er functions later in this chapter!

Chapter /=& Introduction to Inheritance Kirtual Destructors ,n important topic we have i&nored so far is virtual destructors! Consider the followin& two classes=
*lass Pase5lass { $ubli*4 Pase5lass(); cPase5lass(); #; *lass 9erived5lass" public VaseHlass { $ubli*4 9erived5lass(); c9erived5lass(); $rivate4 *har3 m%6tring; #; 9erived5lass449erived5lass() { myItring O new charR1(,S; "" Allo*ate some memor% # 9erived5lass44c9erived5lass() { delete RS myItring; "" 9eallo*ate the memor% #

1 A6? 1

/ere- we have a trivial constructor and destructor for Pase5lass! 9erived5lass- on the other hand- has a constructor and destructor that allocate and deallocate a #lock of memory! 0hat happens if we write the followin& code>
Pase5lass3 m%5lass = ne' 9erived5lass; delete myHlassE

'ntuitively- you'd think that since m%5lass points to a 9erived5lass o#*ect- the 9erived5lass destructor would invoke and clean up the dynamically1allocated memory! Unfortunately- this is not the case! The m%5lass pointer is statically1typed as a Pase5lass 3 #ut points to an o#*ect of type 9erived5lass- so delete m%5lass results in unde$ined behavior! The reason for this is that we didn't let C++ know that it should check to see if the o#*ect pointed at #y a Pase5lass 3 is really a 9erived5lass when callin& the destructor! Undefined #ehavior is never a &ood thin&- so to fi) this we mark the Pase5lass destructor virtual! Unlike the other virtual functions we've encountered- thou&h- derived class destructors do not replace the #ase class destructors! 'nstead- when invokin& a destructor virtuallyC++ will first call the derived class destructor- then the #ase class destructor! 0e thus chan&e the two class declarations to look like this=
*lass Pase5lass { $ubli*4 Pase5lass(); #irtual cPase5lass(); #;

1 A66 1
*lass 9erived5lass4 $ubli* Pase5lass { $ubli*4 9erived5lass(); c9erived5lass(); $rivate4 *har 3m%6tring; #;

Chapter /=& Introduction to Inheritance

There is one more point to address here- the pure virtual destructor! 7ecause virtual destructors do not act like re&ular virtual functions- even if you mark a destructor pure virtual- you must still provide an implementation! Thus- if we rewrote Pase5lass to look like
*lass Pase5lass { $ubli*4 Pase5lass(); #irtual cPase5lass() = 0; #;

0e'd then need to write a trivial implementation for the Pase5lass destructor- as shown here=
Pase5lass44cPase5lass() { "" 9o nothing #

This is an unfortunate lan&ua&e 5uirk- #ut you should #e aware of it since this will almost certainly come up in the future! 4untime Costs of Kirtual 2unctions Tirtual functions are incredi#ly useful and syntactically concise- #ut e)actly how efficient are they> ,fter all- a virtual function call invokes one of many possi#le functions- and somehow the compiler has to determine which version of the function to call! There could #e an ar#itrarily lar&e num#er of derived classes overridin& the particular virtual function- so a nagve s'it*h statement that checks the type of the o#*ect would #e prohi#itively e)pensive! 8ortunately- most C++ compilers use a particularly clever implementation of virtual functions that- while slower than re&ular function calls- are much faster than what you may have initially e)pected! Consider the followin& classes=
*lass Pase5lass { $ubli*4 virtual cPase5lass() {# "" <ol%mor$hi* *lasses need virtual destru*tors virtual void do6omething(); $rivate4 int baseR, baseS; #; *lass 9erived5lass4 $ubli* Pase5lass { $ubli*4 virtual void do6omething(); "" =verride Pase5lass version $rivate4 int derR, derS; #;

Chapter /=& Introduction to Inheritance Then the in1memory representation of a 9erived5lass o#*ect looks like this=
Address 8000 #tableG 800G 800F 808E 808N baseR baseS derR derS 2- =eri#edHlass)speci*ic members 2- VaseHlass members

1 A6D 1

,s #efore- we see the Pase5lass mem#ers followed #y the 9erived5lass mem#ers- #ut there is now another piece of data in this o#*ect= the #tableG- or vtable"pointer! This vta#le1pointer is a pointer to the virtual $unction table! 0henever you create a class containin& one or more virtual functions- C++ will create a ta#le containin& information a#out that class that includes metadata a#out the class alon& with a list of function pointers for each of the virtual functions in that class! 8or e)ample- here's a dia&ram of a Pase5lass o#*ect- a 9erived5lass o#*ect- and their respective virtual function ta#les= #tableG baseR baseS VaseHlass Ob6+*t #tableG baseR baseS derR derS =eri#edHlass Ob6+*t The virtual function ta#le for Pase5lass #e&ins with metadata a#out the Pase5lass type- then has two function pointers ( one for the Pase5lass destructor and one for Pase5lass's implementation of do6omething! The 9erived5lass virtual function ta#le similarly contains information a#out 9erived5lass- as well as function pointers for the destructor and do6omething mem#er functions! 'f you'll notice- the virtual function ta#les for Pase5lass and 9erived5lass have the mem#er functions listed in the same order- with the destructor first and then do6omething! This allows C++ to invoke virtual functions 5uickly and efficiently! Suppose that we have the followin& code=
Pase5lass3 m%<tr = Iandom5han*e(0.H)T new VaseHlass 4 new =eri#edHlass; my1tr-:doIomething34E delete my1trE

Pase5lass M+tadata destru*tor do6omething

Cod+ 5or Pase5lass d+&tr0*tor Cod+ 5or Pase5lass44do6omething

9erived5lass M+tadata destru*tor do6omething

Cod+ 5or 9erived5lass d+&tr0*tor Cod+ 5or 9erived5lass44do6omething

1 A6E 1

Chapter /=& Introduction to Inheritance

0e assi&n a random o#*ect to m%<tr that is either a Pase5lass or a 9erived5lass usin& the Iandom5han*e function we wrote in the chapter on Snake! 0e then invoke the do6omething mem#er function on the o#*ect and then delete it! To implement this functionality- the C++ compiler compiles the second two lines into machine code that performs the followin& operations=
// my1tr-:doIomething34E

1. ook at the first four #ytes of the o#*ect pointed at #y m%<trQ this is the vtable3 for the o#*ect! 2. 8ollow the vtable3 and retrieve the second function pointer from the ta#leQ this corresponds to do6omething! 3. Call this function!
// delete my1trE

1. ook at the first four #ytes of the o#*ect pointed at #y m%<tr! 2. 8ollow the vtable3 and retrieve the first function pointer from the ta#leQ this corresponds to the destructor! 3. Call this function! 4. 2eallocate the memory pointed at #y m%<tr! This se5uence of commands can #e e)ecuted 5uickly and is efficient no matter how many su#classes of Pase5lass e)ist! 'f there are millions of derived classes- this code still only has to make a sin&le lookup throu&h the virtual function ta#le to call the proper function! ,lthou&h this a#ove implementation of virtual function calls is considera#ly more efficient than a nagve approach- it is still noticea#ly slower than a re&ular function call #ecause of the necessary virtual function ta#le lookups! This e)tra overhead is the reason that C++ re5uires you to e)plicitly mark mem#er functions you want to treat polymorphically virtual ( if all functions were called this way- you would pay a performance hit irrespective of whether you actually used inheritance- a violation of the zero1overhead principle! In;oking Kirtual (ember 2unctions @on&Kirtuall/ 8rom time to time- you will need to #e a#le to e)plicitly invoke a #ase class's version of a virtual function! 8or e)ample- suppose that you're desi&nin& a 0%brid5ar that's a specialization of 5ar- #oth of which are defined #elow=
*lass 5ar { $ubli*4 virtual c5ar(); "" <ol%mor$hi* *lasses need virtual destru*tors #irtual #oid applyVra'es34E #irtual #oid accelerate34E #; *lass 0%brid5ar" public Har { $ubli*4 #irtual #oid applyVra'es34E #irtual #oid accelerate34E $rivate4 void *hargePatter%(); void dis*hargePatter%(); #;

Chapter /=& Introduction to Inheritance

1 A6< 1

The 0%brid5ar is e)actly the same as a re&ular car- e)cept that whenever a 0%brid5ar slows down or speeds up- the 0%brid5ar char&es and dischar&es its electric motor to conserve fuel! 0e want to implement the a$$l%PraBes and a**elerate functions inside 0%brid5ar such that they perform e)actly the same tasks as the 5ar's version of these functions- #ut in addition perform the e)tra motor mana&ement! 'nitially- we mi&ht consider implementin& these functions like this=
void 0%brid5ar44a$$l%PraBes() { applyVra'es34E // Nh oh... *hargePatter%(); # void 0%brid5ar44a**elerate() { accelerate34E // Nh oh... dis*hargePatter%(); #

The a#ove code is well1intentioned #ut incorrect! ,t a hi&h level- we want to have the hy#rid car accelerate or apply its #rakes #y doin& whatever a re&ular car does- then mana&in& the motor! ,s written- thou&hthese functions will cause a stack overflow- since the calls to a$$l%PraBes() and a**elerate() recursively invoke the 0%brid5ar's versions of these functions over and over! Since this doesn't workwhat other approaches mi&ht we try> 8irst- we could simply copy and paste the code from the 5ar class into the 0%brid5ar class! This should cause you to crin&e ( a &ood solution to a pro#lem should never involve copyin& and pastin& codeR Bore concretely- thou&h- this approach has several pro#lems! 8irst- if we chan&e the implementation of a**elerate() or a$$l%PraBes() in the 5ar class- we have to remem#er to make the same chan&es inside 0%brid5ar! 'f we for&et to do so- the code will compile #ut will #e incorrect! Boreover- if the implementation of a**elerate() or a$$l%PraBes() in the 5ar class reference private data mem#ers or mem#er functions of 5ar- the resultin& code will #e ille&al! This clearly isn't the ri&ht way to solve this pro#lem! 0hat other options are availa#le> , second idea is to factor out the code for a$$l%PraBes and a**elerate into $rote*ted- non1virtual functions of the 5ar class! 8or e)ample=
*lass 5ar { $ubli*4 virtual c5ar(); virtual void a$$l%PraBes() { do.pplyVra'es(); # virtual void a**elerate() { do.ccelerate(); # $rote*ted4 #oid do.pplyVra'es34; "" Kon-virtual fun*tion that a*tuall% slo's do'n. #oid do.ccelerate34; "" Kon-virtual fun*tion that a*tuall% a**elerates. #; *lass 0%brid5ar4 $ubli* 5ar { $ubli*4 virtual void a$$l%PraBes() { do.pplyVra'es34; *hargePatter%(); # virtual void a**elerate() { do.ccelerate34; dis*hargePatter%(); # $rivate4 void *hargePatter%(); void dis*hargePatter%(); #;

1 AD0 1

Chapter /=& Introduction to Inheritance

/ere- the virtual functions a$$l%PraBes and a**elerate are wrapped calls to non1virtual- protected functions written in the #ase class! To implement the derived versions of a$$l%PraBes and a**eleratewe can simply call these functions! This approach is stylistically pleasin&! The code that's common to a$$l%PraBes and a**elerate is factored out into helper mem#er functions- so chan&es to one function appear in the other! 7ut there's one minor pro#lem with this approach= this solution only works if we can modify the 5ar class! 'n small pro*ects this shouldn't #e a pro#lem- #ut if these classes are pieces in a much lar&er system the code may #e off1limits ( may#e it's #ein& developed #y another team- or perhaps it's #een compiled into a pro&ram that e)pects the class definition to precisely match a specific pattern! This idea is clearly on the ri&ht track#ut in some cases cannot work! The optimal solution to this conundrum- however- is to simply have the 0%brid5ar's implementations of these functions directly call the versions of these functions defined in 5ar! 0hen callin& a virtual function throu&h a pointer or reference- C++ ensures that the function call will 4fall down6 to the most derived class's implementation of that function! /owever- we can force C++ to call a specific version of a virtual function #y callin& it usin& the function's fully15ualified name! 8or e)ample- consider this version of the 0%brid5ar.s version o* a$$l%PraBes:
void 0%brid5ar44a$$l%PraBes() { Har""applyVra'es34; "" 5all 5arAs version of a$$l%PraBes, no $ol%mor$hism *hargePatter%(); #

The synta) 5ar44a$$l%PraBes instructs C++ to call the 5ar class's version of a$$l%PraBes! Jven thou&h a$$l%PraBes is virtual- since we've used the fully15ualified name- C++ will not resolve the call at runtime and we are &uaranteed to invoke 5ar's version of the function! 0e can write an a**elerate function for 0%brid5ar similarly! 0hen usin& the fully15ualified1name synta)- you're allowed to access any superclass's version of the function- not *ust the direct ancestor! 8or e)ample- if 5ar were derived from the even more &eneric class &our2heeledJehi*le that itself provides an a$$l%PraBes method- we could invoke that version from 0%brid5ar #y writin& &our2heeledJehi*le44a$$l%PraBes()! .ou can also use the fully15ualified name synta) as a class client- thou&h it is rare to see this in practice! $b%ect Initiali5ation in Deri;ed Classes Fecall from several chapters a&o that class construction proceeds in three steps ( allocatin& space to hold the o#*ect- callin& the constructors of all data mem#ers- and invokin& the o#*ect constructor! 0hile this picture is mostly correct- it omits an important step ( initialization of #ase classes! et's suppose we have the followin& classes=

Chapter /=& Introduction to Inheritance


*lass Pase { $ubli*4 Vase34 " myInt313 40 myItring3FVase stringF4 LM virtual cPase(); $rivate4 int m%(nt; string m%6tring; #; *lass 9erived4 public Vase { $rivate4 ve*tor int) m%Je*tor; #;

1 AD1 1

7ecause we have not defined a constructor for 9erived- C++ will automatically supply it with a defaultzero1ar&ument constructor that invokes the default constructor of the Pase o#*ect! To see what this means- let's trace throu&h the construction of a new 9erived o#*ect! 8irst- C++ &ives the o#*ect a #lock of uninitialized memory with enou&h space to hold all of the parts of the 9erived! This memory looks somethin& like this= ,t this point- C++ will initialize the Pase class usin& its default constructor! Similarly- if Pase has any parent classes- those parent classes would also #e initialized! ,fter this step- the o#*ect now looks like this=

Vase Data $embers int myInt string myItring 13 Jength" 11 %e5t" FVase ItringF

#ector2int: myKector

Ii6e" !!! Elements" !!!

8rom this point forward- construction will proceed as normal!

1 AD; 1

Chapter /=& Introduction to Inheritance

7y default- derived class constructors invoke the default constructor for their #ase classes- or a zero1 ar&ument constructor if one has e)plicitly #een defined! This is often- #ut not always- the desired #ehavior for a class! 7ut what if you want to invoke a different constructor> 8or e)ample- let's return to the 5ar e)ample from earlier in this chapter! Suppose that 5ar e)ports a sin&le constructor that accepts a string encodin& the license num#er! 8or e)ample=
*lass 5ar { $ubli*4 e5plicit Har3const stringP license@um4 " license3license@um4 LM virtual c5ar() {# virtual void a**elerate(); virtual void a$$l%PraBes(); $rivate4 *onst string li*ense; #;

7ecause 5ar no lon&er has a default constructor- the previous definition of 0%brid5ar will cause a compile1time error #ecause the 0%brid5ar constructor cannot call the none)istent default constructor for 5ar! /ow can we tell 0%brid5ar to invoke the 5ar constructor with the proper ar&uments> The answer is similar to how we would construct a data mem#er with a certain value ( we use the initializer list! /ere is a modified version of the 0%brid5ar class that correctly initializes its 5ar #ase class=
*lass 0%brid5ar4 $ubli* 5ar { $ubli*4 e5plicit >ybridHar3const stringP license4 " Har3license4 LM virtual void a$$l%PraBes(); virtual void a**elerate(); $rivate4 void *hargePatter%(); void dis*hargePatter%(); #;

"ote that when usin& initializer lists to initialize #ase classes- you are only allowed to specify the names of direct #ase classes! ,s an e)ample- suppose that we want to create a class called E+$erimental0%brid5ar that is similar to a 0%brid5ar e)cept that it contains e)tra instrumentation to monitor the state of the motor! 7ecause E+$erimental0%brid5ar represents a prototype car- the car does not have a license plate- and so we want to communicate the strin& 4"one6 up to 5ar to represent this information! Then if we define the E+$erimental0%brid5ar class as follows=
*lass E5perimental>ybridHar" public >ybridHar { $ubli*" E5perimental>ybridHar34E virtual void a$$l%PraBes(); virtual void a**elerate(); #;

't would #e ille&al to define the constructor as follows=


"3 Kote4 ;his is not legal 5!!1 3" E+$erimental0%brid5ar44E+$erimental0%brid5ar() 4 Har3F@oneF4 { #

Chapter /=& Introduction to Inheritance

1 AD@ 1

The pro#lem with this code is that 5ar is an indirect #ase class of E+$erimental0%brid5ar and thus cannot #e initialized from the E+$erimental0%brid5ar initializer list! The reason for this is simple! E+$erimental0%brid5ar inherits from 0%brid5ar- which itself inherits from 5ar! 0hat would happen if #oth 0%brid5ar and E+$erimental0%brid5ar each tried to initialize 5ar in their initializer lists> 0hich constructor should take precedence> 'f it's 0%brid5ar- then the initializer list for E+$erimental0%brid5ar would #e i&nored- leadin& to misleadin& code! 'f it's E+$erimental0%brid5ar- then if 0%brid5ar needs to call the 5ar constructor with particular ar&uments- those ar&uments would #e i&nored and 0%brid5ar mi&ht not #e initialized correctly! To avoid this sort of confusion- C++ only lets you initialize direct #ase classes! Thus the proper version of the E+$erimental0%brid5ar constructor is as follows=
"3 ;ell 0%brid5ar to initialiUe itself 'ith the string /Kone/ 3" E+$erimental0%brid5ar44E+$erimental0%brid5ar() 4 >ybridHar3F@oneF4 { #

Since 0%brid5ar forwards its constructor ar&ument up to 5ar- this ends up producin& the correct #ehavior! Kirtual 2unctions in Constructors et's take a 5uick look #ack at class construction for derived classes! 'f you'll recall- #ase classes are initialized #efore any of the derived class data mem#ers are set up! This means that there is a small window when the #ase class constructor e)ecutes where the #ase class is fully set up- #ut nothin& in the derived class has yet #een initialized! 'f the #ase class constructor could somehow access the data mem#ers of the derived class- it would read uninitialized memory and almost certainly crash the pro&ram! 7ut this seems impossi#le ( after all- the #ase class has no idea what's derivin& from it- so how could it access any of the derived class's data mem#ers> Unfortunately- there is one way ( virtual functions! Suppose the #ase class contains a virtual function and that one of the derived classes overrides that function to read a data mem#er of the derived class! 'f the #ase class calls the virtual function in its constructor- it would #e a#le to read the uninitialized value- causin& a potential pro&ram crash! The desi&ners of C++ were well1aware of this ed&e case- and to prevent this error from occurrin& they added a restriction on the #ehavior of virtual function calls inside constructors! 'f you invoke a virtual function inside a class constructor- the function is not invoked polymorphically! That is- the virtual function call will always call the version of the function appropriate for the type of the #ase class rather than the type of the derived class! To see this in action- consider the followin& code=
*lass Pase { $ubli*4 Pase() { fn34E # virtual void fn() { cout 22 FVaseF 22 endlE # #;

1 ADA 1
*lass 9erived" public Vase { $ubli*4 virtual void fn() { cout 22 F=eri#edF 22 endlE # #;

Chapter /=& Introduction to Inheritance

/ere- the Pase constructor invokes its virtual function fn! 0hile normally you would e)pect that this would invoke 9erived's version of fn- since we're inside the #ody of the Pase constructor- the code will e)ecute Pase's version of fn- which prints out 47ase6 instead of the e)pected 42erived!6 Cases where you would invoke a virtual function in a constructor are rare- #ut if you plan on doin& so remem#er that it will not #ehave as you mi&ht e)pect! Jverythin& we've discussed in this section has focused on class constructors- #ut these same restrictions apply to class destructors as well! C++ destructs classes from the outside inward- cleanin& up derived classes #efore #ase classes- and if virtual functions were treated polymorphically inside destructors it would #e possi#le to access data mem#ers of a derived class after they'd already #een cleaned up! Co+/ Constructors and Assignment $+erators for Deri;ed Classes Copy constructors and assi&nment operators are complicated #easts that are even more perilous when mi)ed with inheritance! 'n particular- you must make sure to invoke the copy constructor and assi&nment operator for any #ase classes in addition to any other #ehavior! ,s an e)ample- consider the followin& #ase class- which has a well1defined copy constructor and assi&nment operator=
*lass Pase { $ubli*4 Pase(); Pase(*onst Pase? other); Pase? o$erator= (*onst Pase? other); virtual cPase(); $rivate4 "3 ... im$lementation s$e*ifi* ... 3" #;

"ow- consider the followin& derived class=


*lass 9erived" public Vase { $ubli*4 9erived(); 9erived(*onst 9erived? other); 9erived? o$erator= (*onst 9erived? other); virtual c9erived(); $rivate4 charG theItringE // Itore a H string #oid copyAther3const =eri#edP other4E #oid clear34E #;

Usin& the template outlined in the chapter on copy functions- we mi&ht write the followin& code for the 9erived assi&nment operator and copy constructor=

Chapter /=& Introduction to Inheritance


"3 Generi* /*o$% other/ member fun*tion. 3" void 9erived44*o$%=ther(*onst 9erived? other) { theItring O new charRstrlen3other.theItring4 D 1SE strcpy3theItring0 other.theItring4E # "3 5lear-out member fun*tion. 3" void 9erived44*lear() { delete RS theItringE theItring O @NJJE # "3 5o$% *onstru*tor. 3" 9erived449erived(*onst 9erived? other) "" $rong1 { copyAther3other4E # "3 Assignment o$erator. 3" 9erived? 9erived44o$erator= (*onst 9erived? other) "" $rong1 { if3this !O Pother4 L clear34E copyAther3other4E M return GthisE #

1 AD? 1

'nitially- it seems like this code should work- #ut- alas- it is seriously flawed! 2urin& this copy operationwe never instructed C++ to copy over the data from other's #ase class into the receiver o#*ect's #ase class! ,s a result- we'll end up with half1copied data- where the data specific to 9erived is correctly cloned #ut Pase's data hasn't chan&ed! To see this visually- if we have two o#*ects of type 9erived that look like this= one8& Pase t'o8& Pase

one8& 9erived

t'o8& 9erived

,fter invokin& the copy functions implemented a#ove- the o#*ects would end up in this state= one8& Pase t'o8& Pase

two8& 9erived

t'o8& 9erived

0e now have a partially1copied o#*ect- which will almost certainly crash at some point down the line!

1 AD6 1

Chapter /=& Introduction to Inheritance

0hen writin& assi&nment operators and copy constructors for derived classes- you must make sure to manually invoke the assi&nment operators and copy constructors for #ase classes to &uarantee that the o#*ect is fully1copied! 8ortunately- this is not particularly difficult! et's first focus on the copy constructor! Somehow- we need to tell the receiver's #ase o#*ect that it should initialize itself as a copy of the parameter's #ase o#*ect! 7ecause 9erived is"a Pase- so we can pass the parameter to the 9erived copy constructor as a parameter to Pase's copy constructor inside the initializer list! The updated version of the 9erived copy constructor looks like this=
"3 5o$% *onstru*tor. 3" 9erived449erived(*onst 9erived ?other) " Vase3other4 "" 5orre*t { *o$%=ther(other); #

The code we have so far for the assi&nment operator correctly clears out the 9erived part of the 9erived class- #ut leaves the Pase portion untouched! /ow should we &o a#out assi&nin& the Pase part of the receiver o#*ect the 9erived part of the parameter> Simple ( we'll invoke the Pase's assi&nment operator and have Pase do its own copyin& work! The code for this is a #it odd and is shown #elow=
"3 Assignment o$erator. 3" 9erived? 9erived44o$erator= (*onst 9erived ?other) { if(this 1= ?other) { *lear(); Vase""operatorO 3other4E "" (nvoBe the assignment o$erator from Pase. *o$%=ther(other); # return 3this; #

/ere we've inserted a call to Pase's assi&nment operator usin& the full name of the o$erator = function! This is one of the rare situations where you will need to use the full name of an overloaded operator! 'n case you're curious why *ust writin& 3this = other won't work- remem#er that this calls 9erived's version of o$erator =- causin& infinite recursion! ,ll of the a#ove discussion has assumed that your classes re5uire their own assi&nment operator and copy constructor! /owever- if your derived class does not contain any data mem#ers that re5uire manual copyin& and assi&nment Kfor e)ample- a derived class that simply holds an intL- none of the a#ove code will #e necessary! C++'s default assi&nment operator and copy constructor automatically invoke the assi&nment operator and copy constructor of any #ase classes- which is e)actly what you'd want it to do! Disallowing Co+/ing Usin& inheritance- it's possi#le to ele&antly and concisely disallow copyin& for o#*ects of a certain type! ,s mentioned a#ove- a class's default copy constructor and assi&nment operator automatically invoke the copy constructor and assi&nment operator for any #ase classes! 7ut what if for some reason the derived class can't call those functions> 8or e)ample- suppose that we have the followin& class=

Chapter /=& Introduction to Inheritance


*lass @n*o$%able { $ubli*4 "3 ... 3" $rivate4 Nncopyable3const NncopyableP4E NncopyableP operatorO 3const NncopyableP4E #;

1 ADD 1

,s mentioned in the chapter on copy constructors and assi&nment operators- this class cannot #e copied #ecause the copy constructor and assi&nment operator are marked private! 0hat will happen if we then create a class that inherits from @n*o$%able- as shown here=
*lass :%5lass4 public Nncopyable { "3 ... 3" #;

et's assume that :%5lass does not e)plicitly declare a copy constructor or assi&nment operator! This will cause C++ to try to create a default implementation for these functions! 'n the process of doin& so- the compiler will realize that it needs to call the copy constructor and assi&nment operator of @n*o$%able! 7ut these functions are $rivate- meanin& that the derived class :%5lass can't access them! Father than reportin& this as an error- instead the compiler doesn't create default implementations of these functions! This means that :%5lass has no copy constructor or assi&nment operator- not even default implementations- and thus can't #e copied or assi&ned! 0e've successfully disallowed copyin&R /owever- #y inheritin& from @n*o$%able- we've introduced some undesira#le #ehavior! 't is now le&al for clients of :%5lass to treat :%5lass as thou&h it were an @n*o$%able- as shown here=
:%5lass3 m* = ne' :%5lass; NncopyableG u1tr = m*;

This is unfortunate- since @n*o$%able is an implementation detail of :%5lass- not a supertype! 0e are now in a rather interestin& situation! 0e want to a#sor# the functionality provided #y another class- #ut don't want to make our type a su#type of that class in the process! 'n other words- we want to a#sor# an implementation without its correspondin& inter$ace! 8ortunately- usin& a techni5ue called private inheritance, we can e)press this notion precisely! So far- the inheritance you have seen has #een public inheritance! 0hen a class pu#licly inherits from a #ase class- it a#sor#s the pu#lic interface of the #ase class alon& with any implementations of the functions in that interface! 'n private inheritance- a derived class inherits from a #ase class solely to ac5uire its implementation! 0hile the derived class retains the implementation of all $ubli* mem#er functions from the #ase class- those functions #ecome $rivate in the derived class! 8or e)ample- &iven these two classes=
*lass Pase { $ubli*4 void do6omething(); #; *lass 9erived4 pri#ate Vase { "3 ... 3" #;

1 ADE 1

Chapter /=& Introduction to Inheritance

Chapter /=& Introduction to Inheritance The followin& code is ille&al=


9erived d; d.doIomething34; "" Error

1 AD< 1

Jven thou&h do6omething was declared $ubli* in Pase- #ecause 9erived inherits privately from Pase the do6omething mem#er function is $rivate! ,dditionally- private inheritance does not define a su#typin& relationship! That is- the followin& code is ille&al=
Pase3 $tr = ne' 9erived; "" Error

0hile pu#lic inheritance models the is"a relationship- private inheritance represents the is"implemented" in"terms"o$ relationship! 8or e)ample- we mi&ht use private inheritance to implement a sta*B in terms of a de[ue- since a sta*B's entire functionality can #e e)pressed throu&h proper calls to $ushLfrontfront- and $o$Lfront! This is shown here for a sta*B of inte&ers=
*lass sta*B4 pri#ate de&ue2int: { $ubli*4 void $ush(int val) { push8front3#al4; "" 5alls de[ue int)44$ushLfront. # int $o$() { *onst int result = front34E pop8front34E return result; # "3 ... et*. ... 3" #;

"otice that $ush is implemented as a call to the de[ue's $ushLfront function- while $o$ is implemented throu&h a series of calls to front and $o$Lfront! 7ecause we privately inherited from de[ue int)- our class contains an implementation of all of the de[ue's mem#er functions- and it is as if we have our own private copy of a de[ue that we can work with! Cu#lic and private inheritance are desi&ned for entirely different purposes! 0e use pu#lic inheritance to desi&n a collection of classes lo&ically related to each other #y some common #ehaviors! Crivate inheritance- on the other hand- is an implementation techni5ue used to define one class's #ehaviors in terms of another's! Gne way to remem#er the difference #etween pu#lic and private inheritance is to reco&nize that they play entirely different roles in class desi&n! Cu#lic inheritance is used durin& the desi&n of a class inter$ace Kdeterminin& what #ehaviors the class should provideL- while private inheritance is used durin& desi&n of a class implementation Khow those #ehaviors should #e performedL! This parallels the difference #etween a function prototype and a function definition ( pu#lic inheritance defines a set of prototypes- while private inheritance provides implementations! Crivate inheritance is not fre5uently encountered in practice #ecause the is"implemented"in"terms"o$ relationship can #e modeled more clearly throu&h composition! 'f we wanted to implement a sta*B in terms of a de[ue- instead of usin& private inheritance- we could *ust have the sta*B contain a de[ue as a data mem#er- as shown here=

1 AE0 1

Chapter /=& Introduction to Inheritance

Chapter /=& Introduction to Inheritance


*lass sta*B { $ubli*4 void $ush(int val) { implementation.push8front3#al4; # int $o$() { *onst int result = implementation.front34E implementation.pop8front34E return result; # "3 ... et*. ... 3" $rivate4 de&ue2int: implementationE #;

1 AE1 1

'n practice it is recommended that you shy away from private inheritance in favor of this more e)plicit form of composition! /owever- there are several cases where private inheritance is precisely the tool for the *o#! et's return to our discussion of the @n*o$%able class! Fecall that to make a class uncopya#le- we had it pu#lically inherit from a class @n*o$%able that has its copy functions marked private! This led to pro#lems where we could convert an o#*ect that inherited from @n*o$%able into an @n*o$%able! /owever- we can remedy this #y havin& the derived class inherit privately from @n*o$%able! That way- it is not considered a su#type of @n*o$%able and instances of :%5lass cannot #e converted into instances of @n*o$%able! 8or e)ample=
*lass :%5lass4 pri#ate Nncopyable { "3 ... 3" #;

"ow- :%5lass cannot #e copied- nor can it #e treated as thou&h it were an o#*ect of type @n*o$%able! This is precisely the idea we want to e)press! 'n C++- all inheritance is considered private inheritance unless e)plicitly mentioned otherwiseQ this is why you must write $ubli* Pase to pu#licly inherit from Pase! Thus we can rewrite the a#ove class definition omittin& the $rivate keyword- as shown here=
*lass :%5lass" Nncopyable { "3 ... 3" #;

This method of disallowin& copyin& is particularly ele&ant ( syntactically- we communicate that :%5lass cannot #e copied at the same time that we actually make it uncopya#le throu&h private inheritance! 7efore concludin& this section- let's make a 5uick chan&e to the @n*o$%able class #y markin& its constructor and destructor $rote*ted! This means that classes that inherit from @n*o$%able can still access the constructor and destructor- #ut otherwise these functions are off1limits! This prevents us from accidentally instantiatin& @n*o$%able directly and only lets us use it as a #ase class! The code for this is shown here=

1 AE; 1
*lass @n*o$%able { protected" Nncopyable34 LM QNncopyable34 LM $rivate4 @n*o$%able(*onst @n*o$%able?); @n*o$%able? o$erator= (*onst @n*o$%able?); #;

Chapter /=& Introduction to Inheritance

Classes like @n*o$%able are sometimes referred to as mi4in classes since they are desi&ned to #e 4mi)ed6 into other classes to provide a particular functionality! 6licing 'n our discussion of copy constructor and assi&nment operators for derived classes- we encountered pro#lems when we copied over the the data of the 9erived class #ut not the Pase class! /owever- there's a far more serious pro#lem we can run into called slicing where we copy only the #ase class of an o#*ect while leavin& its derived classes unmodified! Suppose we have two Pase 3 pointers called one and t'o that point to o#*ects either of type Pase or of type 9erived! 0hat happens if we write code like 3one = 3t'o> /ere- we're copyin& the value of the o#*ect pointed at #y t'o into the varia#le pointed at #y one! 0hile at first &lance this mi&ht seem harmless- the a#ove statement is one of the most potentially dan&erous mistakes you can make when workin& with C++ inheritance! The pro#lem is that this line e)pands into a call to
one-)operator O(3t'o);

"ote that the version of o$erator = we're callin& here is the one defined in Pase- not 9erived- so this line will only copy over the Pase portion of t'o into the Pase portion of one- resultin& in half1formed o#*ects that are almost certainly not in the correct state and may #e entirely corrupted! Slicin& can #e even more insidious in scenarios like this one=
void 9o6omething(Pase base=b>e*t) { "" 9o something # 9erived m%9erived 9o6omething(m%9erived);

Fecall that the parameter base=b>e*t will #e initialized usin& the Pase copy constructor- not the 9erived copy constructor- so the o#*ect in 9o6omething will not #e a correct copy m%9erived! 'nstead- it will only hold a copy of the Pase part of the m%9erived o#*ect! .ou should almost never assi&n a #ase class o#*ect the value of a derived class! The second you do- you will open the door to runtime errors as your code tries to use incompletely1formed o#*ects! 0hile it may sound simple to follow this rule- at many times it mi&ht not #e clear that you're slicin& an o#*ect! 8or e)ample- consider this code snippet=
ve*tor Pase) m%PaseJe*tor; Pase3 m%Pase<tr = 6ome&un*tion(); m%PaseJe*tor.$ushLba*B(GmyVase1tr);

Chapter /=& Introduction to Inheritance

1 AE@ 1

/ere- the o#*ect pointed at #y m%Pase<tr could #e of type Pase or any type inheritin& from Pase! 0hen we call m%PaseJe*tor.$ushLba*B(3m%Pase<tr)- there is a &ood chance that we will slice the o#*ect pointed at #y m%Pase<tr- storin& only its Pase component in the ve*tor and droppin& the rest! .ou'll need to #e e)tra vi&ilant when workin& with derived classes- since it's easy to &enerate dan&erousdifficult1to1track #u&s! T.e C99 Casting $+erators Gne of the most useful features of C++ inheritance is the a#ility to use an o#*ect of one type in place of another! 8or e)ample- a pointer of type 9erived 3 can #e used whenever a Pase 3 would #e e)pectedand the conversion is automatic! /owever- in many circumstances- we may want to perform this conversion in reverse! Suppose that we have a pointer that's statically typed as a Pase 3- #ut we know that the o#*ect it points to is actually of typed 9erived 3! /ow can we use the 9erived features of the pointee> 7ecause the pointer to the o#*ect is a Pase 3- not a 9erived 3- we will have to use a typecast to convert the pointer from the #ase type to the derived type! Usin& the typecasts most familiar to us in C++the code to perform this conversion looks as follows=
Pase3 m%Pase<tr; "" Assume 'e Bno' that this $oints to a 9erived ob>e*t. 9erived3 m%9erived<tr = 3=eri#ed G4m%Pase<tr;

There is nothin& wron& with the a#ove code as written- #ut it is risky #ecause of the typecast (9erived 3)m%Pase<tr! 'n C++- usin& a typecast of the form (;%$e) is e)tremely dan&erous #ecause there are only minimal compile1time checks to ensure that the typecast makes any sense! 8or e)ampleconsider the followin& C++ code=
Pase3 m%Pase<tr; "" Assume 'e Bno' that this $oints to a 9erived ob>e*t. ve*tor double)3 m%Je*tor<tr = 3#ector2double: G4m%Pase<tr; "" @h oh1

This code is completely nonsensical- since there is no reasona#le way that a pointer of type Pase 3 can end up pointin& to an o#*ect of type ve*tor double)! /owever- #ecause of the e)plicit pointer1to1pointer typecast- this code is entirely le&al! 'n the a#ove case- it's clear that the conversion we're performin& is incorrect- #ut in others it mi&ht #e more su#tle! Consider the followin& code=
const VaseG m%Pase<tr; "" Assume 'e Bno' that this $oints to a 9erived ob>e*t. =eri#edG m%9erived<tr = 3=eri#ed G4m%Pase<tr;

This code a&ain is totally le&al and at first &lance mi&ht seem correct- #ut unfortunately it contains a serious error! 'n this e)ample- our initial pointer was a pointer to a *onst Pase o#*ect- #ut in the second line we removed that *onstness with a typecast and the resultin& pointer is free to modify the o#*ect it points at! 0e've *ust su#verted *onst- which could lead to a whole host of pro#lems down the line! The pro#lem with the a#ove style of C++ typecast is that it's *ust too powerful! 'f C++ can fi&ure out a way to convert the source o#*ect to an o#*ect of the tar&et type- it will- even if it's clear from the code that the conversion is an error! To resolve this issue- C++ has four special operators called casting operators that you can use to perform safer typecasts! 0hen workin& with inheritance- two of these castin& operators are particularly useful- the first of which is stati*L*ast! The stati*L*ast operator performs a typecast in the same way that the more familiar C++ typecast does- e)cept that it checks at compile time that the cast 4makes sense!6 Bore specifically- stati*L*ast can #e used to perform the followin& conversions=P

P There are several other conversions that you can perform with stati*L*ast- especially when workin& with void pointers- #ut we will not discuss them here!

1 AEA 1

Chapter /=& Introduction to Inheritance

1. Convertin& #etween primitive types Ke!&! int to float or *har to doubleL! 2. Convertin& #etween pointers or references of a derived type to pointers or references of a #ase type Ke!&! 9erived 3 to Pase 3L where the tar&et is at least as *onst as the source! 3. Convertin& #etween pointers or references of a #ase type to pointers or references of a derived type Ke!&! Pase 3 to 9erived 3L where the tar&et is at least as *onst as the source! 'f you'll notice- neither of the errors we made in the previous code snippets are possi#le with a stati*L*ast! 0e can't convert a Pase 3 to a ve*tor double) 3- since Pase and ve*tor double) are not related to each other via inheritance! Similarly- we cannot convert from a *onst Pase 3 to a 9erived 3- since 9erived 3 is less *onst than *onst Pase 3! The synta) for the stati*L*ast operator looks resem#les that of templates and is illustrated #elow=
Pase3 m%Pase<tr; "" Assume 'e Bno' this $oints to a 9erived ob>e*t. 9erived3 m%9erived<tr = static8cast2Uy=eri#ed G:3myVase1tr4;

That is- stati*L*ast- followed #y the type to convert the pointer to- and finally the e)pression to convert enclosed in parentheses! Throu&hout this discussion of typecasts- when convertin& #etween pointers of type Pase 3 and 9erived 3- we have implicitly assumed that the Pase 3 pointer we wanted to convert was pointin& to an o#*ect of type 9erived! 'f this isn't the case- however- the typecast can succeed #ut lead to a 9erived 3 pointer pointin& to a Pase o#*ect- which can cause all sorts of pro#lems at runtime when we try to invoke none)istent mem#er functions or access data mem#ers of the 9erived class that aren't present in Pase! The pro#lem is that the stati*L*ast operator doesn't check to see that the typecast it's performin& makes any sense at runtime! To provide this functionality- you can use another of the C++ castin& operators- dynamic%cast- which acts like stati*L*ast #ut which performs additional checks #efore performin& the cast! d%nami*L*ast- like stati*L*ast- can #e used to convert #etween pointer types related #y inheritance K#ut not to convert #etween primitive typesL! /owever- if the typecast re5uested of d%nami*L*ast is invalid at runtime Ke!&! attemptin& to convert a Pase o#*ect to a 9erived o#*ectLd%nami*L*ast will return a K@77 pointer instead of a pointer to the derived type! 8or e)ample- consider the followin& code=
Pase3 m%Pase<tr = ne' Pase; 9erived3 m%9erived<tr8 = (9erived 3)m%Pase<tr; 9erived3 m%9erived<trE = stati*L*ast 9erived 3)(m%Pase<tr); 9erived3 m%9erived<trC = dynamic8cast2=eri#ed G:(m%Pase<tr);

'n this e)ample- we use three different typecasts to convert a pointer that points to an o#*ect of type Pase to a pointer to a 9erived! 'n the a#ove e)ample- the first two casts will perform the type conversionresultin& in pointers of type 9erived 3 that actually point to a Pase o#*ect- which can #e dan&erous! /owever- the final typecast- which uses d%nami*L*ast- will return a K@77 pointer #ecause the cast cannot succeed! 0hen performin& downcasts Kcasts from a #ase type to a derived typeL- unless you are a#solutely sure that the cast will succeed- you should consider usin& d%nami*L*ast over a stati*L*ast or raw C++ typecast! 7ecause of the e)tra check at runtime- d%nami*L*ast is slower than the other two casts- #ut the e)tra safety is well worth the cost! There are two more interestin& points to take note of when workin& with d%nami*L*ast! 8irst- you can only use d%nami*L*ast to convert #etween types if the #ase class type contains at least one virtual mem#er function! This may seem like a stran&e re5uirement- #ut &reatly improves the efficiency of the

Chapter /=& Introduction to Inheritance

1 AE? 1

lan&ua&e as a whole and makes sense when you consider that it's rare to hold a pointer to a 9erived in a pointer of type Pase when Pase isn't polymorphic! The other important note is that if you use d%nami*L*ast to convert #etween re$erences rather than pointers- d%nami*L*ast will throw an o#*ect of type badL*ast rather than returnin& a 4K@77 reference6 if the cast fails! Consult a reference for more information on badL*ast! Im+licit Interfaces and )*+licit Interfaces 'n the chapter on templates we discussed the concept of an implicit inter$ace- #ehaviors re5uired of a template ar&ument! 8or e)ample- consider a function that returns the avera&e of the values in an ST container of doubles- as shown here=
tem$late t%$ename 5ontainer;%$e) double GetAverage(*onst 5ontainer;%$e? *) { return a**umulate(*.begin(), *.end(), 0.0) " *.siUe(); #

The function GetAverage may #e parameterized over an ar#itrary type- #ut will only compile if the type 5ontainer;%$e e)ports functions begin and end that return iterators over doubles Kor o#*ects implicitly converti#le to doublesL and a siUe function that returns some inte&er type! Contrast this with a similar function that uses inheritance=
*lass 5ontainer { $ubli*4 t%$edef something-dereferenca'le-to-a-dou'le *onstLiterator; #irtual const8iterator begin34 const O 0E #irtual const8iterator end34 const O 0E #; double GetAverage(*onst Hontainer? *) { return a**umulate(*.begin(), *.end(), 0.0) " *.siUe(); #

This function is no lon&er a template an instead accepts as an ar&ument an o#*ect that derives from 5ontainer! 'n many aspects these functions are similar! 7oth of the implementations have a set of constraints enforced on their parameter- which can #e of any type satisfyin& these constraints! 7ut these similarities o#scure a fundamental difference #etween how the two functions work ( at what point the function calls are resolved! 'n the inheritance1#ased version of GetAverage- the calls to begin- end- and siUe are virtual function calls which are resolved at runtime usin& the system descri#ed earlier in this chapter! 0ith the template1#ased version of GetAverage- the version of the begin- end- and siUe functions to call are resolved at compile"time! 0hen you call a template function- C++ instantiates the template #y replacin& all instances of the template ar&ument with a concrete type! Thus if we call the template function GetAverage on a ve*tor int)- the compiler will instantiate GetAverage on ve*tor int) to yield the followin& code=
double GetAverage #ector2int: )(*onst #ector2int:? *) { return a**umulate(*.begin(), *.end(), 0.0) " *.siUe(); #

1 AE6 1

Chapter /=& Introduction to Inheritance

"ow that the template has #een instantiated- it's clear what functions *.begin() and the like correspond to ( they're the ve*tor int)'s versions of those functions! Since those functions aren't virtual- the compiler can hardcode which function is #ein& called and can optimize appropriately! The template version of this function is desira#le from a performance perspective #ut is not always the #est option! 'n particular- while we can pass as a parameter to GetAverage any o#*ect that conforms to the implicit interface- we cannot treat those classes polymorphically! 8or e)ample- in the a#ove case it's perfectly le&al to call GetAverage on a ve*tor double) or a set double)- #ut we cannot write code like this=
5ontainer3 $tr = Iandom5han*e(0.H) T ne' ve*tor double) 4 ne' set double);

Templates and inheritance are desi&ned to solve fundamentally different pro#lems! 'f you want to write code that operates over any type that meets some minimum re5uirements- the template system can help you do so efficiently and concisely provided that you know what types are #ein& used at compile1time! 'f the types cannot #e determined at compile1time- you can use inheritance to descri#e what #ehaviors are e)pected of function ar&uments! (ore to )*+lore 1. (ulti+le In.eritance= Unlike other o#*ect1oriented lan&ua&es like $ava- C++ lets classes inherit from multiple #ase classes! .ou can use this #uild classes that act like o#*ects of multiple types- or in con*unction with mi)in classes to #uild hi&hly1customiza#le classes! 'n most cases multiple inheritance is strai&htforward and simple- #ut there are many situations where it acts counterintuitively! 'f you plan on pursuin& C++ more seriously- #e sure to read up on multiple inheritance! 2. const8cast and reinterpret8cast= C++ has two other conversion operators- *onstL*astwhich can add or remove *onst from a pointer- and reinter$retL*ast- which performs fundamentally unsafe typecasts Ksuch as convertin& an int 3 to a string 3L! 0hile the use hcases of these operators are far #eyond the scope of this class- they do arise in practice and you should #e aware of their e)istences! Consult a reference for more information! 3. T.e Curiousl/ 4ecurring Tem+late !attern KCFTCL= Tirtual functions make your pro&rams run sli&htly slower than pro&rams with non1virtual functions #ecause of the e)tra overhead of the dynamic lookup! 'n certain situations where you want the #enefits of inheritance without the cost of virtual functions- you can use an advanced C++ trick called the curiously recurring template pattern- or CFTC! The CFTC is also known as 4static interfacin&6 and lets you &et some of the #enefits of inheritance without any runtime cost! 4. !olic/ Classes= , nascent #ut popular C++ techni5ue called policy classes com#ines multiple inheritance and templates to desi&n classes that are simultaneously customiza#le and efficient! , full treatment of policy classes is far #eyond the scope of this reader- #ut if you are interested in seein& e)actly how customiza#le C++ can #e ' stron&ly encoura&e you to read more a#out them! !ractice !roblems 1. 'n the Generi*Pat*h<rinter e)ample from earlier in this chapter- recall that the 9o*ument #ase class had several methods defined purely virtually- meanin& that they don't actually have any code for those mem#er functions! 'nside Generi*Pat*h<rinter- why don't we need to worry that the 9o*ument 3 pointer from the [ueue points to an o#*ect of type 9o*ument and thus mi&ht cause pro#lems if we tried invokin& those purely virtual functions> 2. 'n the ne)t e)ercises- we'll e)plore a set of classes that let you #uild and modify functions at runtime usin& tools similar to those in the ST fun*tional) pro&rammin& li#rary!

Chapter /=& Introduction to Inheritance

1 AED 1

Consider the followin& a#stract class=


*lass &un*tion { $ubli*4 virtual c&un*tion() = 0; virtual double evaluateAt(double value) = 0; #; This class e)ports a sin&le function- evaluateAt- that accepts a double as a parameter and returns the value of some function evaluated at that point! 0rite a derived class of &un*tion6im$le&un*tion- whose constructor accepts a re&ular C++ function that accepts and returns a double and whose evaluateAt function returns the value of the stored function evaluated at the

parameter! 3. The composition of two functions 2 and is defined as 2K K*LL ( that is- the function 2 applied to the value of applied to *! 0rite a class 5om$osition&un*tion whose constructor accepts two &un*tion 3 pointers and whose evaluateAt returns the composition of the two functions evaluated at a point! 4. The derivative of a function is the slope of the tan&ent line to that function at a point! The derivative of a function 2 can #e appro)imated as 2>K*L P K2K* + %*L ( 2K* & %*LL H 2%* for small values of %*! 0rite a class 9erivative&un*tion whose constructor accepts a &un*tion 3 pointer and a double representin& %* and whose evaluateAt appro)imates the derivative of the stored function usin& the initial value of %*! . 8or the a#ove classes- why did we make a function named evaluateAt instead of providin& an implementation of o$erator()> 5+int& 'ill we be using actual 9unction ob!ects, or pointers to them(6 !. , common mistake is to try to avoid pro#lems with slicin& #y declarin& o$erator = as a virtual function in a #ase class! 0hy won't this solve the slicin& pro#lem> 5+int& what is the parameter type to operator 2(6 $. Suppose you have three classes- Pase- 9erived- and Jer%9erived where 9erived inherits from Pase and Jer%9erived inherits from 9erived! ,ssume all three have copy constructors and assi&nment operators! 'nside the #ody of Jer%9erived's assi&nment operator- why shouldn't it invoke Pase44o$erator = on the other o#*ect> 0hat does this tell you a#out lon& inheritance chains- copyin&- and assi&nment> 6. The C++ castin& operators were deli#erately desi&ned to take up space to discoura&e pro&rammers from usin& typecasts! J)plain why the lan&ua&e desi&ners frown upon the use of typecasts! 7. The unar%Lfun*tion and binar%Lfun*tion classes from fun*tional) do not define o$erator() as a virtual mem#er function! Considerin& that every adapta#le function must #e a su#class of one of these two classes- it seems lo&ical for the two classes to do so! 0hy don't they> K/int= the ST is desi&ned for ma)imum possi#le efficiency! 0hat would happen if o$erator() was virtual>L

A++endices

A++endi* -8 (o;ing from C to C99


_________________________________________________________________________________________________________

C++ owes a &reat de#t to the C pro&rammin& lan&ua&e! /ad it not #een rooted in C synta)- C++ would have attracted fewer earlier adopters and almost certainly would have vanished into the mists of history! /ad it not kept C's emphasis on runtime efficiency- C++ would have lost relevance over time and would have &one e)tinct! 7ut despite C++'s history in C- C and C++ are very different lan&ua&es with their own idioms and patterns! 't is a common mistake to think that knowled&e of C entails a knowled&e of C++ or vice1versaand e)perience with one lan&ua&e often leads to su#optimal codin& skills in the other! 'n particularpro&rammers with a #ack&round in pure C often use C constructs in C++ code where there is a safer or more ele&ant alternative! This is not to say that C pro&rammers are somehow worse coders than C++ pro&rammers- #ut rather that some patterns en&rained into the C mentality are often incompati#le with the lan&ua&e desi&n &oals of C++! This appendi) lists ten idiomatic C patterns that are either deprecated or unsafe in C++ and su&&ests replacements! There is no new C++ content here that isn't already covered in the main #ody of the course reader- #ut ' hi&hly recommend readin& throu&h it anyway if you have si&nificant #ack&round in C! This #y no means an e)haustive list of differences #etween C and C++- #ut should nonetheless help you transition #etween the lan&ua&es! Ti+ -8 !refer streams to stdio.h C++ contains the C runtime li#rary in its standard li#rary- so all of the 'HG functions you've seen in stdio.h) K$rintf- s*anf- fo$enL are availa#le in C++ throu&h the *stdio) header file! 0hile you're free to use $rintf and s*anf for input and output in C++- ' stron&ly advise you a&ainst doin& so #ecause the functions are inherently unsafe! 8or e)ample- consider the followin& C code=
*har m%6tring[80EG] = {A,0A#; int m%(nt; $rintf(/Enter an integer and a string4 /); s*anf(/\d \80ECs/, ?m%(nt, m%6tring); $rintf(/Sou entered \d and \s,n/, m%(nt, m%6tring);

/ere- we prompt the user for an inte&er and a strin&- then print them #ack out if the user entered them correctly! ,s written there is nothin& wron& with this code! /owever- consider the portions of the code ''ve hi&hli&hted here=
*har m%6tring[10()] = {A,0A#; int m%(nt; $rintf(/Enter an integer and a string4 /); s*anf(/\d \10(3s/, ?m%(nt, m%6tring); $rintf(/Sou entered \d and \s,n/, m%(nt, m%6tring);

Consider the size of the #uffer- 10;A! 0hen readin& input from the user- if we don't e)plicitly specify that we want to read at most 10;@ characters of input- we risk a #uffer overrun that can trash the stack and allow an attacker to fully compromise the system! 0hat's worse- if there is a mismatch #etween the declared size of the #uffer K10;AL and the num#er of characters specified for readin& K10;@L- the compiler will not provide any warnin&s! 'n fact- the only way we would discover the pro#lem is if we were very careful to read over the code checkin& for this sort of mistake- or to run an advanced tool to dou#le1check the code for consistency!

1 A<; 1

Appendi4 %& -oving $rom C to C++

Similarly- consider the hi&hli&hted #its here=

Appendi4 %& -oving $rom C to C++


*har m%6tring[80EG] = {A,0A#; int m%(nt; $rintf(/Enter an integer and a string4 /); s*anf(/Wd W10(3s/, PmyInt, myItring); $rintf(/Sou entered Wd and Ws,n/, myInt, myItring);

1 A<@ 1

"otice that when readin& values from the user or writin& values to the console- we have to e)plicitly mention what types of varia#les we are readin& and writin&! The fact that m%(nt is an int and m%6tring is a *har3 is insufficient for $rintf and s*anfQ we have to mention to read in an int with \d and a strin& with \s! 'f we &et these #ackwards or omit one- the pro&ram contains a #u& #ut will compile with no errors!P ,nother ve)in& point alon& these lines is the parameter list in s*anf ( we must pass in a pointer to m%(nt- #ut can *ust specify m%6tring #y itself! Confusin& these or &ettin& them #ackwards will cause a crash or a compiler warnin&- which is 5uite a price to pay for use input! The pro#lem with the C 'HG li#raries is that they completely #ypass the type system! Fecall that the si&natures of $rintf and s*anf are
int $rintf(*onst *har3 formatting, ...); int s*anf (*onst *har3 formatting, ...);

The ... here means that the caller can pass in any num#er of ar&uments of any type- and in particular this means that the CHC++ compiler cannot do any type analysis to confirm that you're usin& the ar&uments correctly! ,on.t /et the impression that " or "LL are type)sa*e G they.re not G b#t the static type systems they have are desi/ned to prevent r#ntime errors *rom occ#rin/ and s#bvertin/ this system opens the door *or partic#larly nasty errors. 2n p#re ", code li0e the above is the norm. 2n "LL, however, we can write the *ollowin/ code insteadF
int m%(nt; string m%6tring; *out /Enter an int and a string4 /; *in )) m%(nt )) m%6tring; *out /Sou entered / m%(nt / and /

m%6tring

endl;

2* yo#.ll notice, the only time that the types o* m%(nt and m%6tring are mentioned is at the point o* declaration. Hhen readin/ and writin/ m%(nt and m%6tring, the "LL can a#tomatically in*er which version o* o$erator )) and o$erator to call to per*orm 2'3 and th#s there is no chance that we can accidentally read a string val#e into an int or vice)versa. Ioreover, since we.re #sin/ a "LL)style strin/, there is no chance that we.ll enco#nter a b#**er over*low. 2n short, the "LL streams library is A#st plain sa*er than the ro#tines in stdio.h). Hhen wor0in/ in p#re "LL, be wary o* the stdio.h) *#nctions. Oo# are missin/ o#t on the chance to #se the streams library and are e4posin/ yo#rsel* and yo#r code to all sorts o* potential sec#rity v#lnerabilities. Ti+ 18 Gse C99 strings instead of C&st/le strings ife is short- nasty- and #rutish- and with C strin&s it will #e even worse! C strin&s are notoriously tricky to &et ri&ht- have a cryptic ,C'- and are the cause of all sorts of security #u&s! C++ strings- on the other hand- are ele&ant- pretty- and difficult to use incorrectly! 'f you try truncatin& a C++ string at an invalid inde) with erase- the string will throw an e)ception rather than clo##erin& memory! 'f you append data
P Bany compilers will report errors if you make this sort of mistake- #ut they are not re5uired to do so!

1 A<A 1

Appendi4 %& -oving $rom C to C++

to a C++ string- you don't need to worry a#out reallocatin& any memory ( the o#*ect does that for you! 'n short- C strin&s are tricky to &et right - and C++ strings are tricky to &et wrong! 47ut waitR-6 you mi&ht e)claim- 47ecause C strin&s are so low1level- ' can sometimes outperform the heavywei&ht C++ string!6 This is a#solutely true ( #ecause C strin&s are so e)posed- you have a &reat deal of fle)i#ility and control over how the memory is mana&ed and what operations &o on #ehind the scenes! 7ut is it really worth it> /ere's a small samplin& of what can &o wron& if you're not careful with C strin&s= 1. .ou mi&ht write off the end of a #uffer- clo##erin& other data in memory and pavin& the way for a massive security #reach! 2. .ou mi&ht for&et to deallocate the memory- causin& a memory leak! 3. .ou mi&ht overwrite the terminatin& null character- leadin& to a runtime error or incomprehensi#le pro&ram outputs! ,re C strin&s faster than their C++ counterparts> Gf course! 7ut should you nonetheless sacrifice a little speed for the peace of mind that your pro&ram isn't &oin& to let hackers take down your system> ,#solutely! Ti+ 28 Gse C99 t/+ecasts instead of C t/+ecasts 7oth C and C++ have static type systems ( that is- if you try to use a varia#le of one type where a varia#le of another type is e)pected- the compiler will report an error! 7oth C and C++ let you use typecasts to convert #etween types when needed- sometimes safely and sometimes unsafely! C has only one style of typecast- which is conveniently du##ed a 4C1style typecast!6 ,s mentioned in the chapter on inheritance- C1style typecasts are powerful almost to a fault! Convertin& #etween a double and an int uses the same synta) for unsafe operations like convertin& pointers to inte&ers- inte&ers to pointers- *onst varia#les to non1*onst varia#les- and pointers of one type to pointers of another type! ,s a result- it is easy to accidentally perform a typecast other than the one you wanted! 8or e)ample- suppose we want to convert a *har3 pointer to an int3 pointer- perhaps #ecause we're manually walkin& over a #lock of memory! 0e write the followin& code=
*onst *har3 m%<tr = "3 ... 3" int3 m%(nt<tr = 3int G4m%<tr;

"otice that in this typecast we've converted a *onst *har3 to an int3- su#vertin& *onstness! 's this deli#erate> 's this a mistake> 3iven the a#ove code there's no way to know #ecause the typecast does not communicate what sort of cast is intended! 2id we mean to strip off *onstness- convert from a *har3 to an int3- or #oth> C++ provides three castin& operators K *onstL*ast- stati*L*ast- reinter$retL*astL that are desi&ned to clarify the sorts of typecasts performed in your code! Jach performs e)actly one function and causes a compile1time error if used incorrectly! 8or e)ample- if in the a#ove code we only meant to convert from a *onst *har3 to a *onst int3 without strippin& *onstness- we could write it like this=
*onst *har3 m%<tr = "3 ... 3" *onst int3 m%(nt<tr = reinterpret8cast2const intG:(m%<tr);

"ow- if we leave off the *onst in the typecast- we'll &et a compile1time error #ecause reinter$retL*ast can't strip off *onstness! 'f- on the other hand- we want to convert the pointer from a *onst *har3 to a re&ular int3- we could write it as follows=
*onst *har3 m%<tr = "3 ... 3" int3 m%(nt<tr = const8cast2intG:3reinterpret8cast2const intG:3my1tr44E

Appendi4 %& -oving $rom C to C++

1 A<? 1

This is admittedly much lon&er and #ulkier than the ori&inal C version- #ut it is also more e)plicit a#out e)actly what it's doin&! 't also is safer- since the compiler can check that the casts are #ein& used correctly!

1 A<6 1

Appendi4 %& -oving $rom C to C++

0hen writin& C++ code that uses typecasts- make sure that you use the C++1style castin& operators! ,re they len&thy and ver#ose> ,#solutely! 7ut the safety and clarity &uarantees they provide will more than make up for it! Ti+ 38 !refer new and delete to malloc and free 'n C++- you can allocate and deallocate memory either usin& ne' and delete or usin& mallo* and free! 'f you're used to C pro&rammin&- you may #e tempted to use mallo* and free as you have in the past! This can lead to very su#tle errors #ecause ne' and delete do not act the same as mallo* and free! 8or e)ample- consider the followin& code=
string3 one = new string; string3 t'o = static8cast2stringG:3malloc3si6eof string44;

/ere- we create two string o#*ects on the heap ( one usin& ne' and one usin& mallo*! Unfortunately- the strin& allocated with mallo* is a tickin& time#om# waitin& to e)plode! 0hy is this> The answer has to do with a su#tle #ut critical difference #etween the two allocation routines! 0hen you write ne' string- C++ performs two steps! 8irst- it con*ures up memory from the heap so that the new string o#*ect has a place to &o! Second- it calls the string constructor on the new memory location to initialize the string data mem#ers! Gn the other hand- if you write mallo*(siUeof string)- you only perform the memory allocation! 'n the a#ove e)ample- this means that the string o#*ect pointed at #y t'o has the ri&ht size for a string o#*ect- #ut isn't actually a string #ecause none of its data mem#ers have #een set appropriately! 'f you then try usin& the string pointed at #y t'o- you'll &et a nasty crash since the o#*ect is in a &ar#a&e state! To avoid pro#lems like this- make sure that you always allocate o#*ects usin& ne' rather than mallo*! 'f you do end up usin& #oth ne' and mallo* in a C++ pro&ram Kperhaps #ecause you're workin& with le&acy codeL- make sure that you are careful to deallocate memory with the appropriate deallocator function! That is- don't free an o#*ect allocated with ne'- and don't delete an o#*ect allocated with mallo*! mallo* and ne' are not the same thin&- and memory allocated with one is not necessarily safe to clean up with the other! 'n fact- doin& so leads to undefined #ehavior- which can really ruin your day! Ti+ '8 A;oid #oidG !ointers Code in pure C a#ounds with void3 pointers- particularly in situations where a function needs to work with data of any type! 8or e)ample- the C li#rary function [sort is prototyped as
void [sort(void3 elems, siUeLt numElems, siUeLt elem6iUe, int (3*m$&n)(*onst void3, *onst void3));

That's 5uite a mouthful and uses void3 three times ( once for the input array and twice in the comparison function! The reason for the void3 here is that C lacks lan&ua&e1level support for &eneric pro&rammin& and conse5uently al&orithms that need to operate on ar#itrary data have to cater to the lowest common denominator ( raw #its and #ytes! 0hen usin& C's [sort- you have to #e e)tremely careful to pass in all of the ar&uments correctly! 0hen sortin& an array of ints- you must take care to specify that elem6iUe is siUeof(int) and that your comparison function knows to interpret its ar&uments as pointers to ints! Cassin& in a comparison function which tries to treat its ar&uments as #ein& of some other type Kperhaps *har33s or double3sL will cause runtime errors- and specifyin& the size of the elements in the array incorrectly will pro#a#ly cause incorrect #ehavior or a #us error!

Appendi4 %& -oving $rom C to C++

1 A<D 1

Contrast this with C++'s sort al&orithm=

1 A<E 1

Appendi4 %& -oving $rom C to C++

tem$late t%$ename IandomA**ess(terator, t%$ename 5om$arator) void sort(IandomA**ess(terator begin, IandomA**ess(terator end, 5om$arator *);

0ith C++'s sort- the compiler can determine what types of elements are stored in the ran&e N begin- endL #y lookin& at the type of the iterator passed as a parameter! The compiler can thus automatically fi&ure out the size of the elements in the ran&e! Boreover- if there is a type mismatch #etween what values the 5om$arator parameter accepts and what values are actually stored in the ran&e- you'll &et a compile1time error directin& you to the particular template instantiation instead of a difficult1to1dia&nose runtime error! This e)ample hi&hli&hts the key weakness of void3 ( it completely su#verts the CHC++ type system! 0hen usin& a void3 pointer- you are tellin& the compiler to for&et all type information a#out what's #ein& pointed at and therefore have to e)plicitly keep track of all of the relevant type information yourself! 'f you make a mistake- the compiler won't reco&nize your error and you'll have to dia&nose the pro#lem at runtime! Contrast this with C++'s template system! C++ templates are stron&ly1typed and the compiler will ensure that everythin& type1checks! 'f the pro&ram has a type error- it won't compile- and you can dia&nose and fi) the pro#lem without havin& to run the pro&ram! 0henever you're thinkin& a#out usin& a void3 in C++ pro&rammin&- make sure that it's really what you want to do! There's almost always a way to replace the void3 with a template! Then a&ain- if you want to directly manipulate raw #its and #ytes- void3 is still your #est option! Gne point worth notin&= 'n pure C- you can implicitly convert #etween a void3 pointer and a pointer of any type! 'n C++- you can implicitly convert any pointer into a void3- #ut you'll have to use an e)plicit typecast to convert the other way! 8or e)ample- the C code
int3 m%Arra% = mallo*(numElems 3 siUeof(int));

2oes not compile in C++ since mallo* returns a void3! 'nstead- you'll need to write
int3 m%Arra% = 3int G4mallo*(numElems 3 siUeof(int));

Gr- even #etter- as


int3 m%Arra% = static8cast2int G:(mallo*(numElems 3 siUeof(int)));

Usin& the C++ stati*L*ast operator! Ti+ #8 !refer #ector to raw arra/s ,rrays live in a sort of nether universe! They aren't 5uite varia#les- since you can't assi&n them to one another- and they're not 5uite pointers- since you can't reassi&n where they're pointin&! ,rrays can't remem#er how #i& they are- #ut when &iven a static array you can use siUeof to &et the total space it occupies! 8unctions that operate on arrays have to either &uess the correct size or rely on the caller to supply it! 'n short- arrays are a #it of a mess in C and C++! Contrast this with the C++ ve*tor! vectors know e)actly how lar&e they are- and can tell you if you ask! They are first1class varia#les that you can assi&n to one another- and aren't implicitly converti#le to pointers! Gn top of that- they clean up their own messes- so you don't need to worry a#out doin& your own memory mana&ement! 'n short- the ve*tor is everythin& that the array isn't! 'n addition to #ein& safer than re&ular arrays- vectors can also #e much cleaner and easier to read! 8or e)ample- consider the followin& C code=

Appendi4 %& -oving $rom C to C++


void :%&un*tion(int siUe) { int3 arr = mallo*(siUe 3 siUeof(int)); memset(arr, 0, siUe 3 siUeof(int)); "3 ... 3" free(arr); #;

1 A<< 1

Compare this to the e5uivalent C++ code=


void :%&un*tion(int siUe) { #ector2int: #ec3si6e4E "3 ... 3" #;

"o u&ly computations a#out the size of each element- no messy cleanup code at the end- and no memsets! $ust a sin&le line and you &et the same effect! Boreover- since the ve*tor always cleans up its memory after it &oes out of scope- the compiler will ensure that no memory is leaked! 'sn't that nicer> Gf course- there are times that you mi&ht want to use a fi)ed1size array- such as if you know the size in advance and can fit the array into a struct! 7ut in &eneral- when &iven the choice #etween usin& arrays and usin& vectors- the ve*tor is the more natural choice in C++! Ti+ N8 A;oid goto For a number o$ years I have been $amiliar with the observation that the @uality o$ programmers is a decreasing $unction o$ the density o$ go to statements in the programs they produce -ore recently I discovered why the use o$ the go to statement has such disastrous e$$ects, and I became convinced that the go to statement should be abolished $rom all Phigher levelP programming languages 5i e everything e4cept, perhaps, plain machine code6 ( Jds&er 2i*kstra N2i*6EO The goto keyword #een widely criticised since 2i*kstra pu#lished 43o To Statement Considered /armful6 in 1<6E- yet still mana&ed to make its way into C and conse5uently C++! 2espite its apparent simplicitygoto can cause all sorts of pro&rammin& ni&htmares #ecause it is inherently unstructured! goto can *ump pretty much anywhere and conse5uently can lead to unintuitive or even counterintuitive code! 8or e)ample- here's some code usin& goto=
int + = 0; start4 if (+ == 80) goto out; $rintf(/\d,n/, +); !!+; goto start; out4 $rintf(/9one1,n/);

This is completely e5uivalent to the much more reada#le


for(int + = 0; + 80; !!+)

1 ?00 1
$rintf(/\d,n/, +);

Appendi4 %& -oving $rom C to C++

Appendi4 %& -oving $rom C to C++

1 ?01 1

2espite goto's #ad reputation- modern C pro&rammin& still has several places in which goto can still #e useful! 8irst- goto can #e used as a sort of 4super breaB6 to #reak out of multiple levels of loop nestin&! This use is still le&itimate in C++- #ut is frowned upon stylistically! Second- goto can #e used as a way of performin& necessary cleanup in an error condition! 8or e)ample=
"3 Ieturns a string of the first num5hars *hara*ters from a file or K@77 in an 3 error *ase. 3" *har3 Iead&rom&ile(*onst *har3 filename, siUeLt num5hars) { &(7E3 f; *har3 buffer; "3 Allo*ate some s$a*e. 3" buffer = mallo*(num5hars ! 8); if(buffer == K@77) return K@77; "3 =$en the file, abort on error. 3" f = fo$en(filename, /rb/); if(f == K@77) goto error; "3 Iead the first num5hars *hara*ters, failing if 'e donAt read enough. 3" if(fread(buffer, num5hars, 8, f) 1= num5hars) goto error; "3 5lose the file, null-terminate the string, and return. 3" f*lose(f); buffer[num5hars] = A,0A; return buffer; "3 =n error, *lean u$ the resour*es 'e o$ened. 3" error4 free(buffer); if(f 1= K@77) f*lose(f); return K@77; #

/ere- there are several error conditions in which we need to clean up the temporary #uffer and potentially close an open file! 0hen this happens- rather than duplicatin& the cleanup code- we use goto to *ump to the error1handlin& su#routine! 'n pure C this is perfectly fine- #ut in C++ would #e considered a &ross error #ecause there are much #etter alternatives! ,s mentioned in the chapter on e)ception handlin&- we could instead use a catch1and1 rethrow strate&y to &et the e)act same effect without goto- as shown here=

1 ?0; 1

Appendi4 %& -oving $rom C to C++

"3 Ieturns a string of the first num5hars *hara*ters from a file. 3 ;hro's a runtimeLerror on error. 3" *har3 Iead&rom&ile(*onst *har3 filename, siUeLt num5hars) { &(7E3 f; *har3 buffer = K@77; try { "3 Allo*ate some s$a*e. ;his 'ill thro' on error rather than returning 3 K@77. 3" buffer = ne' *har[num5hars ! 8]; "3 =$en the file, abort on error. 3" f = fo$en(filename, /rb/); if(f == K@77) throw runtime8error3FHanTt open file!F4E "3 Iead the first num5hars *hara*ters, failing if 'e donAt read enough. 3" if(fread(buffer, num5hars, 8, f) 1= num5hars) throw runtime8error3FHanTt read enough characters!F4E "3 5lose the file, null-terminate the string, and return. 3" f*lose(f); buffer[num5hars] = A,0A; return buffer; # catch3...4 { "3 =n error, *lean u$ the resour*es 'e o$ened. 3" delete [] buffer; if(f 1= K@77) f*lose(f); # # throw;

"ow that we're usin& e)ception1handlin& instead of goto- the code is easier to read and allows the caller to &et additional error information out of the function! ,n even #etter alternative here would #e to use an ifstream and a string to accomplish the same result! Since the ifstream and string classes have their own destructors- we don't need to e)plicitly clean up any memory! This is shown here=

Appendi4 %& -oving $rom C to C++


"3 Ieturns a string of the first num5hars *hara*ters from a file. 3 ;hro's a runtimeLerror on error. 3" string Iead&rom&ile(*onst *har3 filename, siUeLt num5hars) { string buffer(num5hars); "3 =$en the file, abort on error. 3" ifstream in$ut(filename); if(input.fail34) thro' runtimeLerror(/5anAt o$en the file1/); "3 Iead the first num5hars *hara*ters, failing if 'e donAt read enough. 3" input.read3PbufferR0S0 numHhars4E if(input.fail34) thro' runtimeLerror(/5ouldnAt read enough data/); return buffer; #

1 ?0@ 1

This version is very clean and concise and doesn't re5uire any goto1like structure at all! Since the o#*ect destructors take care of all of the cleanup- we don't need to worry a#out doin& that ourselves! By advice a&ainst goto also applies to set>m$ and long>m$! These functions are #est replaced with C++'s e)ception1handlin& system- which is far safer and easier to use! Ti+ 78 Gse C99>s bool t/+e w.en a++licable Crior to C<<- the C pro&rammin& lan&ua&e lacked a standard bool type and it was common to find idioms such as
enum bool {true, false#;

Gr
.define bool int .define true 8 .define false 0

Similarly- to loop indefinitely- it was common to write


'hile(8) { "3 ... 3" #

Gr
for(;;) { "3 ... 3" #

2efinin& your own custom bool type is risky in C++ #ecause a custom type will not interact with lan&ua&e features like templates and overloadin& correctly! Similarly- while #oth of the 4loop forever6 loop constructs listed a#ove are le&al C++ code- they are #oth less reada#le than the simpler

1 ?0A 1

Appendi4 %& -oving $rom C to C++

Appendi4 %& -oving $rom C to C++


while3true4 { "3 ... 3" #

1 ?0? 1

'f you aren't already used to workin& with bools- ' su&&est that you #e&in doin& so when workin& in C++! Sure- you can emulate the functionality of a bool usin& an int- #ut doin& so o#scures your intentions and leads to all sorts of other messes! 8or e)ample- if you try to emulate bools usin& ints- you can &et into nasty scrapes where two ints each representin& true don't compare e5ual #ecause they hold different nonzero values! This isn't possi#le with the bool type! To avoid su#tle sources of error and to make your code more reada#le- try to use bool whenever applica#le! Ti+ ,8 A;oid Ptypedef structQ 'n pure C- if you define a struct like this=
stru*t $oint; { int +, %; #;

Then to create an instance of the struct you would declare a varia#le as follows=
struct point% m%<oint;

'n C++- this use of stru*t is unnecessary! 't is also #ad practice- since veteran C++ pro&rammers will almost certainly have to pause and think a#out e)actly what the code means! Gf course- most C pro&rammers are also not particularly fond of this synta)- and to avoid havin& to spell out stru*t each time would write
typedef struct point%8 { int +, %; # $oint;;

This synta) is still valid C++- #ut is entirely unnecessary and makes the code si&nificantly trickier to read! Boreover- if you want to add constructors or destructors to the stru*t you would have to use the name $oint;L even thou&h e)ternally the o#*ect would #e called $oint; without the underscore! This makes the code more difficult to read and may confuse class clients! 'n the interests of clarity- avoid this use of t%$edef when writin& C++ code! Ti+ "8 A;oid memcpy and memset 'n pure C- code like the followin& is perfectly normal=
stru*t $oint; { int +, %; #; stru*t $oint; m%<oint; memset3Pmy1oint0 00 si6eof3point%44E

1 ?06 1

Appendi4 %& -oving $rom C to C++

/ere- the call to memset is used to initialize all the varia#les in the $oint; to zero! Since C lacks constructors and destructors- this code is a reasona#ly &ood way to ensure that the $oint; is initialized #efore use!

Appendi4 %& -oving $rom C to C++

1 ?0D 1

7ecause C++ a#sor#ed C's standard li#rary- the functions memset- mem*$%- and the like are all availa#le in C++! /owever- usin& these functions can lead to su#tle #ut dan&erous errors that can cause all sorts of runtime woes! 8or e)ample- consider the followin& code=
string one = /;his is a string1/; string t'o = /( liBe this string more./; memcpy3Pone0 Ptwo0 si6eof3string44; "" 6et one e[ual to t'o Q does this 'orBT

/ere- we use mem*$% to set one e5ual to t'o! 'nitially- it mi&ht seem like this code works- #ut unfortunately this mem*$% results in undefined #ehavior and will almost certainly cause a runtime crash! The reason is that the string o#*ect contains pointers to dynamically1allocated memory- and when mem*$%in& the data from t'o into one we've made #oth of the strin& o#*ects point to the same memory! ,fter each pointer &oes out of scope- #oth will try to reclaim the memory- causin& pro#lems when the underlyin& strin& #uffer is dou#ly1deleted! Boreover- if this doesn)t immediately crash the pro&ramwe've also leaked the memory one was ori&inally usin& since all of its data mem#ers were overwritten without first #ein& cleaned up! 'f we wanted to set one e5ual to t'o- we could have *ust written this instead=
string one = /;his is a string1/; string t'o = /( liBe this string more./; two O one;

This uses the string's assi&nment operator- which is desi&ned to safely perform a deep copy! 'n &eneral- mi)in& mem*$% with C++ classes is *ust askin& for trou#le! Bost classes maintain some comple) invariants a#out their data mem#ers and what memory they reference- and if you mem*$% a #lock of data over those data mem#ers you mi&ht destroy those invariants! mem*$% doesn't respect $ubli* and $rivate- and thus completely su#verts the encapsulation safe&uards C++ tries to enforce! 7ut the pro#lem runs deeper than this! Suppose that we have a polymorphic class representin& a #inary tree node=
*lass Pinar%;reeKode { $ubli*4 Pinar%;reeKode(); virtual cPinar%;reeKode(); "" <ol%mor$hi* *lasses need virtual destru*tors "3 ... et*. ... 3" $rivate4 Pinar%;reeKode3 left, 3right; #;

0e want to implement the constructor so that it sets left and right to K@77- indicatin& that the node has no children! 'nitially- you mi&ht think that the followin& code is safe=
Pinar%;reeKode44Pinar%;reeKode() { "3 Zero out this ob>e*t. (s this safeT 3" memset3this0 00 si6eof3Vinary%ree@ode44E #

Since the null pointer has value zero- it seems like this should work ( after all- if we overwrite the entire o#*ect with zeros- we've effectively nulled out all of its pointer data mem#ers! 7ut this code is a recipe for

1 ?0E 1

Appendi4 %& -oving $rom C to C++

disaster #ecause the class contains more than *ust a left and right pointer! 'n the chapter on inheritance- we outlined how virtual functions are implemented usin& a virtual function ta#le pointer that sits at the #e&innin& of the class! 'f we use memset to clear out the o#*ect- we'll overwrite this virtual function ta#le pointer with K@77- meanin& that any attempt to call a virtual function on this o#*ect will result in a null pointer dereference and a pro&ram crash!P The key pro#lem with memset and mem*$% is that they completely su#vert the a#stractions C++ provides to increase pro&ram safety! Jncapsulation is supposed to prevent clients from clo##erin& critical class components and o#*ect layout is done automatically specifically to prevent pro&rammers from havin& to e)plicitly manipulate low1level machinery! memset and mem*$% remove these #arriers and e)pose you to dan&erous you could otherwise do without! This is not to say- of course- that memset and mem*$% have no place in C++ code ( they certainly do ( #ut their role is considera#ly less prominent than in pure C! 7efore you use low1level manipulation routinesmake sure that there isn't a #etter way to accomplish the same &oal throu&h more 4le&itimate6 C++ channels! 0ith that said- welcome to C++R Jn*oy your stayR

P This e)ample is #ased on a conversation ' had with Jdward uon&- who encountered this very pro#lem when writin& a lar&e pro&ram in C++!

A++endi* 18 6olutions to !ractice !roblems


_________________________________________________________________________________________________________

Streams
Problem 2. There are two steps necessary to /et 0as0e+7etters wor0in/. Jirst, we trans*orm the inp#t n#mber into a strin/ representation o* its he4adecimal val#e. -e4t, #sin/ techniE#es similar to that *or Get(nteger, we chec0 to see i* this strin/ can be interpreted as an int when read in base 10. 2* so, the he4adecimal representation o* the n#mber m#st not contain any letters (since letters can.t be interpreted as a decimal val#e), otherwise the representation has at least one letter in it. 3ne possible implementation is /iven hereF
bool 0as0e+7etters(int value) { "3 &unnel the data into a stringstream, using the he+ mani$ulator to re$resent 3 it in he+ade*imal. 3" stringstream *onverter; *onverter he5 value; "3 Ko', tr% e+tra*ting the string as an int, using the de* mani$ulator to read 3 it in de*imal. 3" int dumm%; *onverter )) dec )) dumm%; "3 (f the stream failed, 'e *ouldnAt read an int and 'eAre done. 3" if(*onverter.fail()) return true; "3 =ther'ise, tr% reading something else from the stream. (f 'e su**eed, it 3 must have been a letter and 'e Bno' that the integer has letters in its he+ 3 re$resentation. 3" *har leftover; *onverter )) leftover; # return 1*onverter.fail();

ST& Containers' (art )


Problem 5a. 2* we want to cycle the elements o* a container, then o#r best options are the de[ue and the [ueue. &oth o* these choices let #s E#ic0ly move the *ront element o* the container to the bac05 the de[ue with $o$Lfront and $ushLba*B and the [ueue with $ush and $o$. "yclin/ the elements o* a sta*B is impossible witho#t havin/ some e4ternal str#ct#re that can store the sta*B.s data, so this is not a /ood choice. Hhile it.s possible to cycle the elements o* a ve*tor #sin/ $ushLba*B and erase, doin/ so is very ine**icient beca#se the ve*tor will have to sh#**le all o* its elements down to *ill in the /ap at the be/innin/ o* the container. <emember, i* yo# ever want to add and remove elements at the be/innin/ or end o* a ve*tor, the de[ue is a better choice.

1 ?10 1

Appendi4 /& ,olutions to Practice Problems

Problem 5b. Jor this sol#tion we.ll #se an %TB [ueue, since we don.t need access to any element o* the 0ey list e4cept the *irst. Then one sol#tion is as *ollowsF
string Jigenere5i$her(string toEn*ode, [ueue int) values) { for(int B = 0; B toEn*ode.length(); !!B) { toEncodeR'S DO #alues.front34E "" En*r%$t the *urrent *hara*ter #alues.push3#alues.front344E "" Add the *urrent Be% to the ba*B. #alues.pop34E "" Iemove the *urrent Be% from the front. # #

ST& )terators
Problem 5. 3ne possible implementation o* the *#nction is as *ollowsF
ve*tor string) 7oadAll;oBens(string filename) { ve*tor string) result; "3 =$en the file, if 'e *anAt, >ust return the em$t% ve*tor. 3" ifstream in$ut(filename.*Lstr()); if(in$ut.fail()) return result; "3 @sing the istreamLiterator iterator ada$ter, read ever%thing out of the 3 file. 6in*e b% default the streams librar% uses 'hites$a*e as a se$arator 3 *hara*ter, this reads in all of the toBens. 3" result.insert3result.begin340 istream8iterator2string:3input40 istream8iterator2string:344E # return result;

ST& Containers' (art ))


Problem 2. He can solve this problem by loadin/ all o* the val#es in the ma$ into a ma$ string, int) associatin/ a val#e in the initial ma$ with its *reE#ency. He then can /et the n#mber o* d#plicates by addin/ #p all o* the entries in the second ma$ whose val#e is not one (i.e. at least two elements have the same val#e). This can be implemented as *ollowsF

Appendi4 /& ,olutions to Practice Problems


int Kum9u$li*ateJalues(ma$ string, string)? in$ut) { ma$ string, int) *ounter;

1 ?11 1

"3 (terate over the ma$ u$dating the fre[uen*% *ount. Koti*e that 'e are 3 *he*Bing for the number of du$li*ate #alues, so 'eAll inde+ into the ma$ b% 3 looBing at itr-)se*ond. Also note that 'e donAt *he*B for the *ase 'here 3 the ma$ doesnAt alread% *ontain this Be%. 6in*e 6;7 *ontainers initialiUe 3 all stored integers to Uero, if the Be% doesnAt e+ist a fresh $air 'ill be 3 *reated 'ith value Uero. 3" for(ma$ string, string)44iterator itr = in$ut.begin(); itr 1= in$ut.end(); !!itr) DDcounterRitr-:secondSE int result = 0; "3 Ko' iterate over the entries and a**umulate those that have at least value 3 t'o. 3" for(ma$ string, string)44iterator itr = in$ut.begin(); itr 1= in$ut.end(); !!itr) if(itr-)se*ond ) 8) result != itr-)se*ond; return result; #

Problem 5. There are many /ood sol#tions to this problem. Iy personal *avorite is this oneF
void 5ount7etters(ifstream? in$ut, ma$ *har, int)? fre[:a$) { *har *h; 'hile(in$ut.get(*h)) !!fre[:a$[*h]; #

This code is dense and relies on several properties of the stream li#rary and the ST ! 8irst- the mem#er function get accepts as input a *har #y reference- then reads in a sin&le character from the stream! Gn success- the function fills the *har with the read value! Gn failure- the value is unchan&ed and the stream &oes into a fail state! The get function then returns a reference to the stream o#*ect that did the readin&meanin& that 'hile(in$ut.get(*h)) is e5uivalent to
'hile(true) { in$ut.get(*h); if(1in$ut) breaB; "3 ... bod% of loo$ ... 3" #

,nd since 1in$ut is e5uivalent to in$ut.fail()- this one1liner will read in a character from the file- then #reak out of the loop if the read failed! 3nce we.ve read in the character, we can simply write !!fre[:a$[*h], since i* the 0ey already e4ists we.re incrementin/ the older val#e and i* not a new 0ey'val#e pair will be created with val#e 0, which is then incremented #p to one.

1 ?1; 1

Appendi4 /& ,olutions to Practice Problems

Problem 6. +s mentioned in the hint, the tric0 is to #se the str#ct#re o* le4ico/raphic comparisons to constr#ct a pair o* strin/s lower) and #pper)bo#ndin/ all strin/s with the /iven pre*i4. Jor e4ample, s#ppose that we want to *ind all words be/innin/ with the pre*i4 anti. -ow, any word be/innin/ with anti m#st compare le4ico/raphically /reater than or eE#al to anti, since the *irst *o#r characters will match b#t the word be/innin/ with anti m#st also be lon/er than anti. Jor e4ample, antigen and antidisestablishmentarianism both compare /reater than anti since they have the same pre*i4 as anti b#t are lon/er. The ne4t observation is that any word that doesn't start with anti *alls into one o* two cate/ories G those that compare le4ico/raphically less than anti and those that compare le4ico/raphically /reater than anti. The *irst o* these sets can be i/nored, b#t how can we *ilter o#t words with non) anti pre*i4es that compare le4ico/raphically /reater than anti: The tric0 is to note that i* the word doesn.t have anti as a pre*i4, then somewhere in its *irst *o#r letters it m#st disa/ree with anti. 2* we ta0e the ne4t le4ico/raphically)hi/her pre*i4 than anti (which is *ormed by incrementin/ the last letter), we /et ant>. This is the smallest possible pre*i4 any word not startin/ by anti can have. Ioreover, every word that starts with anti compares le4ico/raphically less than ant>, and so i* we only loo0 at words that compare le4ico/raphically /reater than or eE#al to anti and le4ico/raphically less than ant>, we have all o* the words that start with anti. @sin/ the set.s lo'erLbound *#nction, we can *ind which words in the set match these criteria e**iciently (in 3(l/ n) time) #sin/ the *ollowin/ codeF
void <rint:at*hing<refi+es(set string)? le+i*on, string $refi+) { "3 2eAll assume the $refi+ is nonem$t% in this ne+t ste$. 3" string ne+t<refi+ = $refi+; DDne5t1refi5Rne5t1refi5.si6e34 - 1SE "3 5om$ute the range to iterate over. 2e store these iterators outside of the 3 loo$ so that 'e donAt have to re*om$ute them ever% time. 3" set string)44iterator end = le5icon.lower8bound3ne5t1refi54; for(set string)44iterator itr = le5icon.lower8bound3prefi54E itr 1= end; !!itr) *out 3itr endl;

ST& A gorithms
Problem 1. Printin/ o#t a ve*tor is easy than0s to ostreamLiterator and *o$%. <ecall that an ostreamLiterator is an iterator which prints o#t the val#es stored in it to *out, and that the *o$% al/orithm accepts three inp#ts G two iterators de*inin/ a ran/e to copy and one iterator representin/ the destination G then copies the inp#t ran/e to the o#tp#t so#rce. Th#s we can print o#t a ve*tor as *ollowsF
void <rintJe*tor(ve*tor int)? v) { copy3#.begin340 #.end340 ostream8iterator2int:3cout0 F F44E #

Problem 4. &y de*a#lt, i* yo# compare two strin/s to one another #sin/ , the res#lt is whether the *irst strin/ le4ico/raphically precedes the second strin/. Th#s i* we have a ve*tor string) called v, callin/ sort(v.begin(), v.end()) will sort the inp#t le4ico/raphically. 2n o#r case, tho#/h, we want to Chac0D the sort *#nction so that it always p#ts CIe Jirst1D at the *ront o* the sorted orderin/. To do this, we.ll write a c#stom callbac0 *#nction that per*orms a de*a#lt strin/ comparison i* neither strin/ is CIe Jirst1D b#t which s0ews the res#lt otherwise. Here.s one implementationF

Appendi4 /& ,olutions to Practice Problems


*onst string B2inner6tring = /:e &irst1/; bool Piased6ort0el$er(string one, string t'o) { "3 5ase one4 Keither string is the 'inner string. 3 *om$arison. 3" if(one 1= B2inner6tring ?? t'o 1= B2inner6tring) return one t'o; "3 5ase t'o4 Poth strings are the 'inner string. 3 string isnAt less than itself. 3" if(one == B2inner6tring ?? t'o == B2inner6tring) return false;

1 ?1@ 1

_ust do a default

;hen return false be*ause the

"3 5ase three4 one is the 'inner string, t'o isnAt. 3 the sort so that the 'inner string *omes first. 3" if(one == B2inner6tring) return true;

Ieturn true to bias

"3 =ther'ise, t'o is the 'inner string and one isnAt 3" return false;

The implementation o* Piased6ort is then


void Piased6ort(ve*tor string)? v) { sort(v.begin(), v.end(), ViasedIort>elper) #

Problem 6 3ne implementation is as *ollowsF


int *ount(ve*tor int)44iterator start, ve*tor int)44iterator end, int value) { int result = 0; for(; start 1= end; !!start) if(3start == value) !!result; # return result;

2n the chapter on templates, yo#.ll see how to /enerali=e this *#nction to operate over any type o* iterators.

(ointers an! References


Problem 5. 2* we allocate memory by writin/ int3 m%(nt<tr = ne' int, "LL will only /ive #s space to hold a sin/le inte/er. However, the code m%(nt<tr[0] = GE is per*ectly sa*e. <ecall that m%(nt<tr[0] means to /o to the address pointed at by m%(nt<tr, move *orward =ero elements, then ret#rn the val#e there. &#t this is eE#ivalent to A#st loo0in/ #p the obAect directly pointed at by m%(nt<tr, and in *act m%(nt<tr[0] = GE is completely eE#ivalent to 3m%(nt<tr = GE. However, m%(nt<tr[8] = GE instr#cts "LL to access the element one a*ter the element pointed at by m%(nt<tr. He don.t own the memory a*ter o#r sin/le int, so this line writes 42 into a memory location. 2t probably will res#lt in some sort o* crash, either immediately or later on when the memory allocator /ets con*#sed.

1 ?1A 1

Appendi4 /& ,olutions to Practice Problems

C Strings
Problem /! The code m%6tring = /6tring/ ! A1A *ust loo*s ri&ht- doesn't it> 't seems like we're concatenatin& an e)clamation point on to the end of a strin& and then assi&nin& the new strin& to m%6tring! /ad we #een workin& with C++ string o#*ects- this would #e true- #ut remem#er that /6tring/ is a C strin& and that ! means pointer arithmetic rather than concatenation! 'n fact- what this code does is o#tain a pointer to the strin& /6tring/ somewhere in memory- then advance that pointer #y the numerical value of the e)clamation point character Kthirty1threeL and store the resultin& pointer in m%6tring! This results in a strin& that's pointin& into random memory we don't own- resultin& in KsurpriseRL undefined #ehavior!

T.e !re+rocessor
Problem ? This restriction e)ists #ecause the preprocessor is a compile"time construct whereas functions are a runtime construct! That is- the code that you write for a function is e)ecuted only when the pro&ram already runs- and preprocessor directives e)ecute #efore the pro&ram #e&ins runnin& Kor has even finished compilin&- for that matterL! 'f a preprocessor directive were to e)ecute a C++ function- the compiler would need to compile and run that function durin& preprocessin&- which mi&ht cause dependency issues if the function referenced code that hadn't yet #een preprocessed- or would have to defer preprocessin& to runtime- defeatin& the entire purpose of the preprocessor! Problem !. The code *or a not)reached macro is act#ally simpler than that *or an assert macro beca#se we don.t need to veri*y any conditions and instead can immediately abort. He can be/in by writin/ the code that act#ally per*orms the action associated with the not)reached statementF
void 9o5680N7KotIea*hed(string message, int line, string filename) { *err /5680N7KotIea*hed failed4 / message endl; *err /7ine number4 / line endl; *err /&ilename4 / filename endl; abort(); # .define 5680N7KotIea*hed(msg) =oHI10+J@otBeached3msg0 88JI@E880 88?IJE884

-e4t, we need to disable the macro in case K=L5680N7LK=;IEA50E9 is de*ined. This can be done as *ollowsF
#ifndef @A8HI10+J8@A%BE.H>E= void 9o5680N7KotIea*hed(string message, int line, string filename) { *err /5680N7KotIea*hed failed4 / message endl; *err /7ine number4 / line endl; *err /&ilename4 / filename endl; abort(); # .define 5680N7KotIea*hed(msg) 9o5680N7KotIea*hed(msg, LL7(KELL, LL&(7EKA:ELL) #else #define HI10+J@otBeached3msg4 /G @othing G/ #endif

Appendi4 /& ,olutions to Practice Problems

1 ?1? 1

1 ?16 1

Appendi4 /& ,olutions to Practice Problems

Problem 11. +ddin/ a K=;LAL5=7=I sentinel to the 5olor en#meration is m#ch easier than it so#nds. The ( Iacro code we have *or /eneratin/ the 5olor en#meration is c#rrently
enum 5olor { .define 9E&(KEL5=7=I(*olor, o$$osite) color0 "" Kame follo'ed b% *omma .in*lude /*olor.h/ .undef 9E&(KEL5=7=I #;

These preprocessor directives e4pand o#t to the *#ll list o* colors with a comma *ollowin/ the name o* the last color. Th#s all we need to do is chan/e the code to loo0 li0e thisF
enum 5olor { .define 9E&(KEL5=7=I(*olor, o$$osite) *olor0 "" Kame follo'ed b% *omma .in*lude /*olor.h/ .undef 9E&(KEL5=7=I @A%8.8HAJAB #;

-ow, the enum contains a constant called K=;LAL5=7=I that *ollows all other colors. Problem 1". He want to chan/e the de*inition o* the 5olor en#meration so that the names o* the colors are pre*aced with e5olorL. Th#s the code we want to /enerate sho#ld loo0 li0e thisF
enum 5olor { e5olorLIed, e5olorLGreen, "3 ... 3" e5olorL2hite #;

<ecall that the ori/inal ( Iacro code we had *or a#tomatically /eneratin/ the 5olor en#meration was
enum 5olor { .define 9E&(KEL5=7=I(*olor, o$$osite) color0 "" Kame follo'ed b% *omma .in*lude /*olor.h/ .undef 9E&(KEL5=7=I #;

He can modi*y this to /enerate the above code by #sin/ the to0en)pastin/ operator ** to concatenate e5olorL be*ore the name o* each o* the colors. The res#ltin/ code is
enum 5olor { .define 9E&(KEL5=7=I(*olor, o$$osite) eHolor8##color0 .in*lude /*olor.h/ .undef 9E&(KEL5=7=I #;

)ntro!+ction to Temp ates


Problem 1. *o$%Lif accepts *o#r parameters G two iterators de*inin/ an inp#t ran/e, one iterator de*inin/ the o#tp#t ran/e, and a predicate *#nction determinin/ whether we sho#ld copy a partic#lar element. %ince we can provide any sort o* inp#t iterator, any sort o* o#tp#t iterator, and a predicate that co#ld theoretically accept any type, we.ll templati=e *o$%Lif over the types o* the ar/#ments, as shown hereF

Appendi4 /& ,olutions to Practice Problems


template 2typename InputIterator0 typename AutputIterator0 typename 1redicate: inline AutputIterator *o$%Lif(InputIterator start, InputIterator end, AutputIterator 'here, 1redicate fn) { "3 ... 3" #

1 ?1D 1

-ote that altho#/h the type o* the predicate *#nction depends on the type o* iterators (that is, i* we.re iteratin/ over strings we can.t /ive a *#nction acceptin/ an int), we.ve templati=ed the *#nction with respect to the predicate. This /ives the client more leeway in what predicates they can provide. Jor e4ample, i* the iterators iterate over a ve*tor int), they co#ld provide a predicate *#nction acceptin/ a double. Bater when we cover *#nctors yo#.ll see a more /eneral reason to templati=e the predicate parameter. -ow all that.s le*t to do is write the *#nction body. Jort#nately this isn.t too tric0y G we A#st 0eep advancin/ the start iterator *orward, chec0in/ i* the element iterated over passes the predicate and copyin/ the element i* necessary. The *inal code loo0s li0e thisF
tem$late t%$ename (n$ut(terator, t%$ename =ut$ut(terator, t%$ename <redi*ate) inline =ut$ut(terator *o$%Lif((n$ut(terator start, (n$ut(terator end, =ut$ut(terator 'here, <redi*ate fn) { for3E start !O endE DDstart4 L if3fn3Gstart44 L Gwhere O GstartE DDwhereE M M return whereE #

+s an JO2, yo# will sometimes see the code


3'here = 3start; !!'here;

Hritten as
3'here!! = 3start;

This is a tric0 that relies on the *act that the !! operator binds more ti/htly than the 3 operator. Th#s the code is interpreted as 3('here!!) = 3start, meanin/ that we advance the 'here iterator by one step, then store in the location it #se to point at the val#e o* 3start. 2 personally *ind this synta4 more attractive than the lon/hand version, b#t it is admittedly more con*#sin/.

1 ?1E 1 Problem 6. <ecall that the code *or Get(nteger is as *ollowsF


int Get(nteger() { 'hile(true) { stringstream *onverter(Get7ine()); int result; *onverter )) result; if(1*onverter.fail()) { *har leftover; *onverter )) leftover;

Appendi4 /& ,olutions to Practice Problems

# else *out # # *out

if(*onverter.fail()) return result; *out /@ne+$e*ted *hara*ter4 / leftover /<lease enter an integer./ endl;

endl;

/Ietr%4 /;

To templati=e this *#nction over an arbitrary type, we need to chan/e the ret#rn type, the type o* result, and the error messa/e abo#t enterin/ an inte/er. The modi*ied code is shown hereF
template 2typename Kalue%ype: Kalue%ype GetJalue(string type) { 'hile(true) { stringstream *onverter(Get7ine()); Kalue%ype result; *onverter )) result; if(1*onverter.fail()) { *har leftover; *onverter )) leftover; if(*onverter.fail()) return result; *out /@ne+$e*ted *hara*ter4 / leftover # else *out *out # # /<lease enter / type endl; endl;

/Ietr%4 /;

const
Problem 5. +t *irst it seems li0e it sho#ld be sa*e to convert an int 33 into a *onst int 33. +*ter all, we.re A#st addin/ more *onsts to the pointer, which restricts what we sho#ld be able to do with the pointer. How co#ld we possibly #se this to s#bvert the type system: The answer is the *ollowin/ chain o* assi/nments that allow #s to overwrite a *onst intF

Appendi4 /& ,olutions to Practice Problems


const int myHonstant O 13 ; "" 7egal int G e#il1tr; "" 7egal, uninitialiUed

1 ?1< 1

"3 ;his ne+t line is not legal 5!! be*ause Pe#il1tr is an intGG and bad1tr is a 3 const int GG. 2at*h 'hat ha$$ens if 'e allo' this. 3" const intGG bad1tr O Pe#il1trE "3 9ereferen*e bad<tr and assign it the address of myHonstant. PmyHonstant is a 3 const int G and bad1tr is a const intG, so the assignment is legal. 0o'ever, 3 sin*e bad1tr $oints to e#il1tr, this assigns e#il1tr the address of the 3 myHonstant variable, 'hi*h is *onst1 3" Gbad1tr O PmyHonstantE "3 ;his 'ould over'rite a *onst variable. 3" Ge#il1tr O )(E

This is a s#btle ed/e case, b#t beca#se it.s possible "LL e4plicitly disallows it. Problem 6. The initial inter*ace *or the "%10!&'( Je*tor class is reprinted hereF
tem$late t%$ename Elem;%$e) *lass Je*tor { $ubli*4 Je*tor(int siUe0int = 0); int siUe(); bool isEm$t%(); Elem;%$e getAt(int inde+); void setAt(int inde+, Elem;%$e value); Elem;%$e ? o$erator[](int inde+); void add(Elem;%$e elem); void insertAt(int inde+, Elem;%$e elem); void removeAt(int inde+); void *lear(); void ma$All(void (3fn)(Elem;%$e elem)); tem$late t%$ename 5lient9ata;%$e) void ma$All(void (3fn)(Elem;%$e elem, 5lient9ata;%$e ? data), 5lient9ata;%$e ? data); (terator iterator(); #;

The *irst tas0 in *onst)correctin/ this is mar0in/ non)m#tatin/ operations *onst. This is reasonably strai/ht*orward *or most o* the *#nctions. The interestin/ case is the o$erator[] *#nction, which ret#rns a re*erence to the element at a /iven position. This *#nction needs to be *onst)overloaded since i* the Je*tor is *onst we want to hand bac0 a *onst re*erence and i* the Je*tor is non)*onst we want to hand bac0 a non*onst re*erence. The #pdated inter*ace is shown hereF

1 ?;0 1
tem$late t%$ename Elem;%$e) *lass Je*tor { $ubli*4 Je*tor(int siUe0int = 0); int siUe() const; bool isEm$t%() const; Elem;%$e getAt(int inde+) const; void setAt(int inde+, Elem;%$e value); Elem;%$e ? o$erator[](int inde+); const Elem%ype P operatorRS3int inde54 constE void add(Elem;%$e elem); void insertAt(int inde+, Elem;%$e elem); void removeAt(int inde+); void *lear();

Appendi4 /& ,olutions to Practice Problems

void ma$All(void (3fn)(Elem;%$e elem)) const; tem$late t%$ename 5lient9ata;%$e) void ma$All(void (3fn)(Elem;%$e elem, 5lient9ata;%$e ? data), 5lient9ata;%$e ? data) const; (terator iterator() const; #;

-e4t, we.ll #pdate the class by passin/ all appropriate parameters by re*erence)to) *onst rather than by val#e. This res#lts in the *ollowin/ inter*aceF
tem$late t%$ename Elem;%$e) *lass Je*tor { $ubli*4 Je*tor(int siUe0int = 0); int siUe() *onst; bool isEm$t%() *onst; Elem;%$e getAt(int inde+) *onst; void setAt(int inde+, const Elem;%$eP value); Elem;%$e ? o$erator[](int inde+); *onst Elem;%$e ? o$erator[](int inde+) *onst; void add(const Elem;%$eP elem); void insertAt(int inde+, const Elem;%$eP elem); void removeAt(int inde+); void *lear(); void ma$All(void (3fn)(const Elem;%$eP elem)) *onst; tem$late t%$ename 5lient9ata;%$e) void ma$All(void (3fn)(const Elem;%$eP elem, 5lient9ata;%$e ? data), 5lient9ata;%$e ? data) *onst; #; (terator iterator() *onst;

Appendi4 /& ,olutions to Practice Problems

1 ?;1 1

Jinally, we.ll chan/e the ret#rn type o* getAt to ret#rn a *onst re*erence to the element in the Je*tor rather than a *#ll copy, since this red#ces the cost o* the *#nction. The *inal version o* the Je*tor is shown belowF
tem$late t%$ename Elem;%$e) *lass Je*tor { $ubli*4 Je*tor(int siUe0int = 0); int siUe() *onst; bool isEm$t%() *onst; const Elem;%$eP getAt(int inde+) *onst; void setAt(int inde+, *onst Elem;%$e? value); Elem;%$e ? o$erator[](int inde+); *onst Elem;%$e ? o$erator[](int inde+) *onst; void add(*onst Elem;%$e? elem); void insertAt(int inde+, *onst Elem;%$e? elem); void removeAt(int inde+); void *lear(); void ma$All(void (3fn)(*onst Elem;%$e? elem)) *onst; tem$late t%$ename 5lient9ata;%$e) void ma$All(void (3fn)(*onst Elem;%$e? elem, 5lient9ata;%$e ? data), 5lient9ata;%$e ? data) *onst; #; (terator iterator() *onst;

static
Problem 2. The @ni[uel%(dentified class can be implemented by havin/ a static variable inside the class that trac0s the most recently #sed 2,, as well as a non)static variable *or each instance that trac0s the partic#lar class.s #niE#e 2,. This can be implemented as *ollowsF
*lass @ni[uel%(dentified { $ubli*4 @ni[uel%(dentified(); int get@ni[ue(9() *onst; $rivate4 static int lastNsedI=E *onst int *urrent(9; #; "3 Iemember, this must go outside the *lass1 3" int Nni&uelyIdentified""lastNsedI= O 1E @ni[uel%(dentified44@ni[uel%(dentified() 4 currentI=3lastNsedI=4 { DDlastNsedI=E #

1 ?;; 1
int @ni[uel%(dentified44get@ni[ue(9() *onst { return *urrent(9; #

Appendi4 /& ,olutions to Practice Problems

Conversion Constr+ctors
Problem 5. "LL will only apply at most one conversion constr#ctor at a time to avoid /ettin/ into ambi/#o#s sit#ations. Jor e4ample, s#ppose that we start o** with types +, &, and " s#ch that + is convertible to & and & is convertible to ". Then we can thin0 o* this /raphically as *ollowsF

-ow, s#ppose we introd#ce another conversion into this mi4, this time directly *rom + to ", as shown hereF

2* we try to implicitly convert *rom an + to a ", which seE#ence o* conversions is correct: ,o we *irst convert the + to a & and then convert that to a ", or A#st directly convert the + to a ": There.s no clear ri/ht answer here, and to avoid con*#sions li0e this "LL sidesteps the iss#e by only applyin/ one implicit conversion at a time.

Copy Constr+ctors an! Assignment Operators


Problem 1. The reason that this code is problematic is that at some point in the assi/nment operator, all o* the reso#rces that were allocated by the c#rrent class instance need to be cleaned #p. However, we never allocated any reso#rces, and none o* the class.s data members have been initiali=ed. Tryin/ to clean #p /arba/e almost always res#lts in a pro/ram crash. 2n /eneral, yo# sho#ld not implement copy constr#ctors in terms o* assi/nment operators Problem 2. 2t is ille/al to write a copy constr#ctor that accepts its parameter by val#e beca#se this ca#ses a circ#lar dependency. <ecall that the copy constr#ctor is invo0ed whenever a *#nction is passed by val#e into a *#nction, so i* the copy constr#ctor itsel* too0 its parameter by val#e it wo#ld need to call itsel* to initiali=e the parameter by val#e, b#t then it wo#ld have to initiali=e the parameter in that *#nction call by invo0in/ itsel*, etc. This ca#ses a compile)time error rather than a r#ntime error, by the way.

Appendi4 /& ,olutions to Practice Problems

1 ?;@ 1

The assi/nment operator doesn.t have this problem beca#se i* the assi/nment operator were to accept its parameter by val#e, the copy is made by the copy constr#ctor, which is an entirely di**erent *#nction.

Operator Over oa!ing


Problem ". The other operators can be de*ined as *ollowsF
A A P = P d d d d d d A 1(P 1(A A 1(A P A P A) P OO P P OO P P) A A)

A == P A 1= P A )= P A ) P

Problem #. Jor re*erence, here.s the bro0en inter*ace o* the iterator classF
*lass iterator { $ubli*4 bool o$erator== (*onst iterator? other); bool o$erator1= (*onst iterator? other); iterator o$erator!! (); Elem;%$e3 o$erator3 () *onst; Elem;%$e3 o$erator-) () *onst; #;

There are *ive problems in this implementation. The *irst two have to do with the declarations o* the == and 1= operators. %ince these *#nctions don.t modi*y the state o* the iterator (or at least, no sensible implementation sho#ld), they sho#ld both be mar0ed *onst, as shown hereF
*lass iterator { $ubli*4 bool o$erator== (*onst iterator? other) const; bool o$erator1= (*onst iterator? other) const; iterator o$erator!! (); Elem;%$e3 o$erator3 () *onst; Elem;%$e3 o$erator-) () *onst; #;

-e4t, ta0e a loo0 at the ret#rn type o* o$erator3. <emember that o$erator3 is called whenever the iterator is dere*erenced. Th#s i* the iterator is pretendin/ to point to an element o* type Elem;%$e, this *#nction sho#ld ret#rn an Elem;%$e? (a re*erence to the val#e) rather than an Elem;%$e3 (a pointer to the val#e). 3therwise code li0e thisF
3m%(tr = 8CD;

Ho#ldn.t compile. The #pdated inter*ace now loo0s li0e thisF

1 ?;A 1
*lass iterator { $ubli*4 bool o$erator== (*onst iterator? other) *onst; bool o$erator1= (*onst iterator? other) *onst; iterator o$erator!! (); Elem;%$eP o$erator3 () *onst; Elem;%$e3 o$erator-) () *onst; #;

Appendi4 /& ,olutions to Practice Problems

-e4t, loo0 at the ret#rn type o* o$erator!!. <ecall that o$erator!! is the pre*i4 !! operator, meanin/ that we sho#ld be able to write code li0e thisF
!!(!!itr)

To increment the iterator twice. @n*ort#nately, with the above inter*ace this code compiles b#t does somethin/ totally di**erent. %ince the ret#rn type is iterator, the ret#rned obAect is a copy o* the receiver obAect rather than the receiver obAect itsel*. Th#s the code !!(!!itr) means to increment itr by one step, then to increment the temporary iterator object by one step. This isn.t at all what we want to do, so we.ll *i4 this by havin/ o$erator!! ret#rn a re*erence to an iterator, as shown hereF
*lass iterator { $ubli*4 bool o$erator== (*onst iterator? other) *onst; bool o$erator1= (*onst iterator? other) *onst; iteratorP o$erator!! (); Elem;%$e? o$erator3 () *onst; Elem;%$e3 o$erator-) () *onst;

#;

He.ve now *i4ed *o#r o* the *ive errors, so what.s le*t: The answer.s a bit s#btle G there.s nothin/ tec$nically wron/ with this inter*ace any more, b#t we.ve le*t o#t an important *#nction that ma0es the inter*ace #nint#itive. 2n partic#lar, we.ve only de*ined a pre*i4 o$erator!! *#nction, meanin/ that code li0e !!itr is le/al b#t not code li0e itr!!. He sho#ld th#s add s#pport *or a post*i4 o$erator!! *#nction. The *inal version o* the iterator class th#s loo0s li0e thisF
*lass iterator { $ubli*4 bool o$erator== (*onst iterator? other) *onst; bool o$erator1= (*onst iterator? other) *onst; iterator? o$erator!! (); const iterator operatorDD 3int4E Elem;%$e? o$erator3 () *onst; Elem;%$e3 o$erator-) () *onst; #;

Appendi4 /& ,olutions to Practice Problems

1 ?;? 1

,+nctors
Problem 1. forLea*h ret#rns the *#nction passed in as a *inal parameter so that yo# can pass in a *#nctor that #pdates internal state d#rin/ the loop and then retrieve the #pdated *#nctor at the end o* the loop. Jor e4ample, s#ppose that we want to comp#te the minim#m, ma4im#m, and avera/e o* a ran/e o* data in a sin/le pass. Then we co#ld write the *ollowin/ *#nctor classF
*lass 9ata6am$le { $ubli*4 /G Honstructor initiali6es minKal and ma5Kal so that theyTre always updated0 G sets the total to 6ero0 and the number of elements to 6ero. G/ 9ata6am$le() 4 minJal((K;L:AR), ma+Jal((K;L:(K), total(0.0), *ount(0) {# /G .ccessor methods. G/ int get:in() *onst { return minJal; # int get:a+() *onst { return ma+Jal; # double getAverage() *onst { return total " *ount; # int getKumElems() *onst { return *ount; # /G operator34 accepts a piece of input and updates state appropriately. G/ void o$erator() (int val) { minJal = min(minJal, val); ma+Jal = ma+(ma+Jal, val); total != val; !!*ount; # $rivate4 int minJal, ma+Jal; double total; int *ount; #;

Then we can write a *#nction which accepts a ran/e o* iterators (pres#med to be iteratin/ over int val#es) and then ret#rns a 9ata6am$le obAect which contains a s#mmary o* that dataF

1 ?;6 1

Appendi4 /& ,olutions to Practice Problems

tem$late t%$ename (n$ut(terator) 9ata6am$le Anal%Ue6am$le((n$ut(terator begin, (n$ut(terator end) { "3 5reate a tem$orar% 9ata6am$le ob>e*t and $ass it through forLea*h. ;his 3 then invoBes o$erator() on*e for ea*h element in the range, resulting in a 3 9ata6am$le 'ith its values set a$$ro$riatel%. 2e then return the result of 3 forLea*h, 'hi*h is the u$dated 9ata6am$le. (snAt that nift%T 3" return for8each3begin0 end0 =ataIample344E #

Problem ". Advan*edPiased6ort is similar to the Piased6ort e4ample *rom the chapter on %TB al/orithms. 2* yo#.ll recall, i* we ass#me that the strin/ that sho#ld be the winner is stored in a constant B2inner6tring, the *ollowin/ comparison *#nction can be #sed to bias the sort so that B2inner6tring always comes in *rontF
bool Piased6ort0el$er(*onst string? one, *onst string? t'o) { "3 5ase one4 Keither string is the 'inner string. _ust do a default 3 *om$arison. 3" if(one 1= B2inner6tring ?? t'o 1= B2inner6tring) return one t'o; "3 5ase t'o4 Poth strings are the 'inner string. 3 string isnAt less than itself. 3" if(one == B2inner6tring ?? t'o == B2inner6tring) return false; ;hen return false be*ause the

"3 5ase three4 one is the 'inner string, t'o isnAt. 3 the sort. 3" if(one == B2inner6tring) return true;

;hen return true to bias

"3 =ther'ise, t'o is the 'inner string and one isnAt, so return false to bias 3 the sort. 3" return false; #

To #pdate this code so that any strin/ can be set as the winner strin/, we.ll need to convert this *#nction into a *#nctor that stores the strin/ as a data member. This can be done as *ollowsF
*lass Piased6ort0el$er { $ubli*4 e+$li*it Piased6ort0el$er(*onst string? 'inner) 4 'inner6tring('inner) {# bool operator34 3const stringP one0 const stringP two4 constE $rivate4 string 'inner6tring; #;

Appendi4 /& ,olutions to Practice Problems


bool ViasedIort>elper""operator34(*onst string? one, *onst string? t'o) *onst { "3 5ase one4 Keither string is the 'inner string. _ust do a default 3 *om$arison. 3" if(one 1= winnerItring ?? t'o 1= winnerItring) return one t'o; "3 5ase t'o4 Poth strings are the 'inner string. 3 string isnAt less than itself. 3" if(one == winnerItring ?? t'o == winnerItring) return false;

1 ?;D 1

;hen return false be*ause the

"3 5ase three4 one is the 'inner string, t'o isnAt. 3 the sort. 3" if(one == winnerItring) return true;

;hen return true to bias

"3 =ther'ise, t'o is the 'inner string and one isnAt, so return false to bias 3 the sort. 3" return false; #

He can then implement Advan*edPiased6ort as *ollowsF


void Advan*edPiased6ort(ve*tor string)? v, *onst string? 'inner) { sort(v.begin(), v.end(), ViasedIort>elper3winner4); #

Problem #. He want to comp#te the val#e o* into *o#r smaller tas0sF 1. 2. 3. 4.

1 x i x 2 n i =1 as applied to a ran/e o* data. This brea0s down

"omp#te the avera/e o* the data set. "omp#te the val#e o* the inner s#m. ,ivide the total by the n#mber o* elements. <et#rn the sE#are root o* this val#e.

He can #se the s[rt *#nction e4ported by *math) to per*orm the sE#are root and a**umulate *or the rest o* the wor0. He.ll be/in by comp#tin/ the avera/e o* the data, as shown hereF
tem$late t%$ename &or'ard(terator) double 6tandard9eviation(&or'ard(terator begin, &or'ard(terator end) { const ptrdiff8t numElems O distance3begin0 end4E const double a#erage O accumulate3begin0 end0 0.04 / numElemsE "3 ... 3" #

-ote that we.ve comp#ted the si=e o* the ran/e #sin/ the distan*e *#nction, which e**iciently ret#rns the n#mber o* elements between two iterators. He.ve stored the n#mber o* elements in a variable o* type $trdiffLt, which, as the name s#//ests, is a type desi/ned to hold the distance between two pointers.

1 ?;E 1

Appendi4 /& ,olutions to Practice Problems

Technically spea0in/ we sho#ld E#ery the iterator *or the type o* val#e ret#rned when comp#tin/ the distance between the iterators, b#t doin/ so is beyond the scope o* this te4t. -ow, let.s see how we can #se a**umulate to eval#ate the s#m. <ecall that the *o#r)parameter version o* a**umulate allows #s to speci*y what operation to apply pairwise to the c#rrent acc#m#lator and any element o* the ran/e. 2n o#r case, we.ll want to add #p the s#m o* the val#es o* ( xi G x)2 *or each element, so we.ll constr#ct a *#nctor that stores the val#e o* the avera/e and whose o$erator() *#nction ta0es the acc#m#lator and the c#rrent element, comp#tes (xi G x)2, then adds it to the c#rrent acc#m#lator. This is shown hereF
*lass 6tandard9eviation0el$er { $ubli*4 e5plicit Itandard=e#iation>elper3double a#erage4 " mean3a#erage4 LM double operator34 3double accumulator0 double currentKalue4 const L const double e5pr O currentKalue X meanE // xi - x return accumulator D e5pr G e5prE // 3xi x4( M $rivate4 const double meanE #;

Kiven this helper *#nctor, we can now write the *ollowin/F


tem$late t%$ename &or'ard(terator) double 6tandard9eviation(&or'ard(terator begin, &or'ard(terator end) { *onst $trdiffLt numElems = distan*e(begin, end); *onst double average = a**umulate(begin, end, 0.0) " numElems; const double sum O accumulate3begin0 end0 0.00 Itandard=e#iation>elper3a#erage44E return s&rt3sum / numElems4E #

Problem %. 2* we were /iven an arbitrary " strin/ and told to set it to the empty strin/, we co#ld do so by callin/ str*$%(m%6tr, //), where m%6tr is the strin/ variable. To do this to every strin/ in a ran/e, we can #se forLea*h to apply the *#nction everywhere and bindEnd to loc0 the second parameter o* str*$% in place. This is shown hereF
tem$late t%$ename &or'ard(tr) void 5learAll6trings(&or'ard(tr begin, &or'ard(tr end) { forLea*h(begin, end, bind(nd3ptr8fun3strcpy40 FF4); #

This wor0s beca#se bindEnd($trLfun(str*$%), //) is a one)parameter *#nction that passes the ar/#ment as the *irst parameter into str*$% with the second parameter loc0ed as the empty strin/. Problem !. -ow that we.re dealin/ with re/#lar "LL strings, we can clear the strin/s by callin/ the .*lear() member *#nction on each o* them. <ecallin/ that the memLfunLref *#nction trans*orms a member *#nction into a one)parameter *#nction that calls the speci*ied *#nction on the ar/#ment, we can write 5learAll6trings as *ollowsF

Appendi4 /& ,olutions to Practice Problems


tem$late t%$ename &or'ard(tr) void 5learAll6trings(&or'ard(tr begin, &or'ard(tr end) { forLea*h(begin, end, mem8fun8ref3Pstring""clear4); #

1 ?;< 1

Problem 11. The re$la*eLif al/orithm ta0es *o#r parameters G two iterators de*inin/ a ran/e o* elements, a predicate *#nction, and a val#e G then replaces all elements in the ran/e *or which the predicate ret#rns tr#e with the speci*ied val#e. 2n o#r case, we.re /iven a val#e as a parameter to the 5a$AtJalue *#nction and want to replace elements in the ran/e that compare /reater than the parameter with the parameter. @sin/ bindEnd and the greater operator *#nction, we have the *ollowin/F
tem$late t%$ename &or'ard(tr, t%$ename Jalue;%$e) void 5a$AtJalue(&or'ard(tr begin, &or'ard(tr end, Jalue;%$e ma+Jalue) { re$la*eLif(begin, end, bind(nd3greater2Kalue%ype:340 ma5Kalue4, ma+Jalue); #

)ntro!+ction to #xception -an! ing


Problem 1. 2* yo# p#t a *at*h(...) cla#se at the top o* a *at*h cascade, then none o* the other *at*h handlers will ever catch e4ceptions thrown by the tr% bloc0. "LL eval#ates each *at*h cla#se in seE#ence #ntil it discovers a match, and i* the *irst is a *at*h(...) it will always choose that one *irst. Problem 4. He want to modi*y the code
void :ani$ulate6ta*B(sta*B string)? m%6ta*B) { if(m%6ta*B.em$t%()) thro' invalidLargument(/Em$t% sta*B1/); string to$Elem = m%6ta*B.to$(); m%6ta*B.$o$(); "3 ;his might thro' an e+*e$tion1 3" 9o6omething(m%6ta*B); m%6ta*B.$ush(to$Elem); #

%o that i* the 9o6omething *#nction throws an e4ception we.re s#re to p#t the element to$Elem bac0 on the sta*B be*ore propa/atin/ the e4ception. This can be done as *ollowsF

1 ?@0 1
void :ani$ulate6ta*B(sta*B string)? m%6ta*B) { if(m%6ta*B.em$t%()) thro' invalidLargument(/Em$t% sta*B1/); string to$Elem = m%6ta*B.to$(); m%6ta*B.$o$(); try L "3 ;his might thro' an e+*e$tion1 3" 9o6omething(m%6ta*B); m%6ta*B.$ush(to$Elem);

Appendi4 /& ,olutions to Practice Problems

M catch3...4 L myItac'.push3topElem4E throwE M # m%6ta*B.$ush(to$Elem);

Problem 5. He want to solve the same problem as in the above case, b#t by #sin/ <+22 to mana/e the reso#rce instead o* man#ally catchin/ and rethrowin/ any e4ceptions. He.ll be/in by de*inin/ an Automati*6ta*B:anager class that ta0es in a re*erence to a sta*B, then pops the top and stores the res#lt internally. Hhen the destr#ctor e4ec#tes, we.ll p#sh the element bac0 on. This loo0s li0e thisF
tem$late t%$ename Elem;%$e) *lass Automati*6ta*B:anager { $ubli*4 e+$li*it Automati*6ta*B:anager(sta*B Elem;%$e)? s) 4 to:anage(s), to$Elem(s.to$()) { to:anage.$o$(); # cAutomati*6ta*B:anager() { to:anage.$ush(to$Elem); # $rivate4 sta*B Elem;%$e)? to:anage; *onst Elem;%$e to$Elem; #;

-otice that we.ve templati=ed this class with respect to the type o* element stored in the sta*B, since there.s nothin/ special abo#t string. This is in /eneral a /ood desi/n philosophy G i* yo# don.t need to speciali=e yo#r code over a sin/le type, ma0e it a template. He can then rewrite the *#nction as *ollowsF

Appendi4 /& ,olutions to Practice Problems


void :ani$ulate6ta*B(sta*B string)? m%6ta*B) { if(m%6ta*B.em$t%()) thro' invalidLargument(/Em$t% sta*B1/); .utomaticItac'Uanager2string: autoHleanup3myItac'4E 9o6omething(m%6ta*B);

1 ?@1 1

-otice how m#ch cleaner and shorter this code is than be*ore G by havin/ obAects mana/e o#r reso#rces we.re s#re that we won.t lea0 any reso#rces here. Tr#e, we had to write a bit o* code *or Automati*6ta*B:anager, b#t provided that we #se it in more than one circ#mstance the savin/s in code simplicity over the man#al catch) and)rethrow approach are impressive.

)ntro!+ction to )nheritance
Problem 1. He don.t have to worry that a pointer o* type 9o*ument3 points to an obAect o* concrete type 9o*ument beca#se 9o*ument is an abstract class and th#s can.t be instantiated. Oo# do not need to worry abo#t a p#re virt#al *#nction call reali=in/ that there.s no act#al code to e4ec#te since "LL will raise a compile)time error i* yo# try to instantiate an abstract class. Problem 4. 3ne possible implementation *or 9erivative&un*tion is shown hereF
*lass 9erivative&un*tion4 $ubli* &un*tion { $ubli*4 e+$li*it 9erivative&un*tion(&un*tion3 to5all) 4 fun*tion(to5all) {# virtual double evaluateAt(double 'here) *onst { *onst double BE$silon = 0.00008; "" 6mall e+ return (function-:e#aluate.t3where D 'Epsilon4 Q function-:e#aluate.t3where - 'Epsilon4) " (E 3 BE$silon); # $rivate4 &un*tion 3*onst fun*tion; #

Here, the constr#ctor accepts and stores a pointer to an arbitary &un*tion, and the evaluateAt *#nction invo0es the virt#al evaluateAt *#nction o* the stored *#nction at the proper points to appro4imate the derivative.

Bibliogra+./
N%tr74QF &Aarne %tro#str#p, &$e 'esign and (volution of )**. +ddison)HesleyF 1774! N%tr07QF &Aarne %tro#str#p. R%tro#str#pF J+SR @<BF http=HHwww!research!att!comHd#sH#s[fa5!htmlSdecline . +ccessed $ T#l 2007! N%te0$QF +le4ander %tepanov. R%hort History o* %TBR @<BF http=HHwww!stepanovpapers!comHhistory b;0ofb;0ST !pdf. +ccessed 2 T#l 2007! N2ntelQF 2ntel "orporation. R7! Udia/ram./i*R @<BF http=HHwww!intel!comHassetsHima&eHdia&ramH<6?[dia&ram!&if. +ccessed $ T#l 2007! NPic7!QF -eilJred Picciotto. R-eil'Jred.s Ki/antic Bist o* PalindromesR @<BF http=HHwww!derf!netHpalindromesHold!palindrome!html. +ccessed 10 T#l 2007! N%tr07.2QF &Aarne %tro#str#p. R%tro#str#pF "LLR @<BF http=HHwww!research!att!comHd#sHC++!html. +ccessed 24 T#n 2007! N%po06QF Toel %pols0y, +oel on ,oft-are .nd on 'iverse and /ccasionally 0elated 1atters &$at 2ill Prove of 3nterest to ,oft-are 'evelopers4 'esigners4 and 1anagers4 and to &$ose 2$o4 2$et$er by 5ood 6ortune or 3ll 7uc84 2or8 -it$ &$em in ,ome )apacity. +pressF 2006! NK-@QF K-@ ProAect. Rstr*ryR @<BF http=HHwww!&nu!or&HsHli#cHmanualHhtml[nodeHstrfry!htmlSstrfry. +ccessed 4 +#/ 2007! N%#t76QF Herb %#tter. R+dvice *rom the "LL V4pertsF &e "onst)"orrectR @<BF http=HHwww!&otw!caHpu#licationsHadvice<E!htm. +ccessed 10 T#n 2007! WI"3QF 1ars )limate /rbiter 1is$ap 3nvestigation 9oard P$ase 3 0eport . -ovember 10, 1777. @<BF ftp=HHftp!h5!nasa!&ovHpu#HpaoHreportsH1<<<HBCG[report!pdf NIey0 QF %cott Ieyers, (ffective )** 55 ,pecific 2ays to 3mprove :our Programs and 'esigns4 &$ird (dition . +ddison)HesleyF 200 ! N%tr07.3QF &Aarne %tro#str#p. R"LL04 J+SR @<BF http=HHwww!research!att!comHd#sHC+ +0)8,M!htmlSthink. +ccessed 10 T#l 2007! N,iA!6QF Vds/er ,iA0stra! WKo To %tatement "onsidered Harm*#l.R )ommunications of t$e .)1, Nol. 11, -o. 3, Iar 17!6, p/. 14$)146

Inde*
A
abort, 1$2, 2$6 uni&ue8ptr, 466

adaptable *#nctions, 3$ , 361 operator *#nctions, 360 address)o* operator, 136 assert, 1$0, 227 assi/nment operators, 2!3 copy)and)swap, 2$$ disablin/, 2$ *or derived classes, 4 2 implementation o*, 2!6 ret#rn val#e o*, 2$2 sel*)assi/nment, 2$0 auto8ptr, 376 and e4ception)sa*ety, 401

B
&"PB,
binary8function, 3$$ bind1st, 3$6

implementation, 36
bind(nd, 3$6, 41!

bitwise eE#ivalence, 2$3 &Aarne %tro#str#p, and p#re virt#al *#nctions, 43$ and the preprocessor, 1!$ &oost "LL libraries, 23 b#sy loop, !3

C
" strin/s, in)memory layo#t, 146 strcat, 1 0 strchr, 1 3 strcmp, 1 1 strcpy, 1 0 strlen, 147 strncpy, 1 3 strstr, 1 2 terminatin/ n#ll, 146 c8str34, 2! "LL04, 461 lambda e4pressions, 467 rval#e re*erences, 46 si6eof..., 474 static8assert, 474 type in*erence, 461

variadic templates, 470 "aesar cipher, 2 castin/ operators, 4 $ const8cast, 0 dynamic8cast, 4 6 reinterpret8cast, 0 static8cast, !4, !!, 4 $, 0$ catch, 373 catch3...4, 37$ cerr, 2! cin, 2 cloc', !3 cloc'8t, !4 HJAH7I81EB8IEH, !3 comple5, 42! const, 20 bitwise constness, 211 const and pointers, 20! const and static, 2 2 const member *#nctions, 20$, 21$ const re*erences, 207, 21! const)correctness, 21 , 262 semantic constness, 211 conversion constr#ctors, 2 , 26 copy constr#ctors, 2!3 disablin/, 2$ *or derived classes, 4 2 implementation o*, 2! copy semantics, 377, 46 cout, 2 ctime, 2!!

D
de*a#lt ar/#ments, 241 defined (preprocessor predicate), 1!2 delete, 142 deleteRS, 144 deterministic *inite a#tomaton, 100 dimensional analysis, 331 distance, 32 d#mb pointer, 31

1 ?@6 1

Inde4

)
e4ception handlin/, 373 and reso#rce lea0s, 37 catch)and)rethrow, 37! reso#rce acE#isition is initiali=ation, 400 e5plicit, 2 6, 26 e4ternal polymorphism, 4$4

(
macros, 1!4 dan/ers o*, 1! ma'e8pair, 74, 10 , 233 malloc, 0! mem8fun, 3$$ mem8fun8ref, 3$$ member initiali=er list, 23$ memory se/ments, 146 mi4in classes, 4 ! monoalphabetic s#bstit#tion cipher, 12 move semantics, 377, 46 mutable, 212

2
free, 0! friend, 30

*#nctors, 3!! as comparison obAects, 3$1 as parameters to *#nctions, 3!7 *#ndamental theorem o* so*tware en/ineerin/, 4!

@
namespace, 16 new, 142 newRS, 144

getline, 34, !1, 214 goto, 06

Ko To %tatement "onsidered Harm*#l, 06 grid, 34

3
hi/her)order pro/rammin/, 3$3

nondeterministic *inite a#tomaton, 10$ not1, 3$7 implementation, 361 not(, 3$7 @NJJ, 141 numeric8limits, 3$3

I
ifstream, 2!, 6, 203, 213

$
obAect constr#ction, 23$ in derived classes, 44! ofstream, 2! operator overloadin/, 271 as *ree *#nctions, 302 compo#nd assi/nment operators, 27$ element selection operator, 27!, 3 2 *#nction call operator, 3!!, 4!7 /eneral principles, 273 increment and decrement operators, 304 mathematical operators, 300, 337 member selection operator, 310, 320 pointer dere*erence operator, 307, 320 relational operators, 30 , 3 ! stream insertion operator, 30$ #nary min#s operator, 277

implicit conversions, 2 incl#de /#ard, 1!3 inheritance, 427 abstract classes, 43$ base classes, 430 copy *#nctions *or derived classes, 4 2 derived classes, 430 disallowin/ copyin/ with, 4 2 *#nction overrides, 436 is)a relationship, 430 polymorphism, 43! private inheritance,, 4 3 p#re virt#al *#nctions, 43$ slicin/, 4 ! inline *#nctions, 1!! in#alid8argument, 374, 423 isalpha, 126 ispunct, 116 isspace, 37, 127

!
pair, 74, 104, 232

=
le4ico/raphical orderin/, 3 $ lval#e, 13$, 274

palindromes, 12$ pointers, 13$ pointer arithmetic, 1 1 pointer assi/nment, 137 pointer dere*erence, 137 #oidG, 0! principle o* least astonishment, 272

Inde4
printf, 04 protected, 440 remo#e8copy8if, 116, 367 remo#e8if, 116, 126 replace8if, 370 re#erse, 126 rotate, 11! set8difference, 11$ set8intersection, 11$ set8symmetric8difference, 11$ set8union, 11$ sort, 11 , 367 swap, 2$$ swap8ranges, 420 transform, 117, 127, 202, 3$3, 41!, 416

1 ?@D 1

pro4y obAects, 3 3 ptr8fun, 3$$ implementation, 364 ptrdiff8t, 32

H
&sort, 0!

4
rand, !!, 2 4 B.@=8U.Y, !!

re*erence co#ntin/, 31 re*erences, 13! row)maAor order, 34! r#le o* three, 2! , 26! rval#e, 274

6
scanf, 04

se/mentation *a#lt, 147 semantic eE#ivalence, 2$3 siblin/ access, 2!$ %im#la, sin/leton class, 2$6 smart pointer, 31 s&rt, 32 srand, !!, 2 4 standard deviation, 367 static, 24$ static data members, 24$ static member *#nctions, 2 1 %TB al/orithms, 113 accumulate, 113, 3$2 binary8search, 11! copy, 116, 2!$, 266, 423 count, 1 ! count8if, 3! e&ual, 11$, 126, 202 fill, 123 find, 11! find8if, 313, 417 for8each, 117, 367 generate, 367 includes, 11$
le5icographical8compare, 3 6 lower8bound, 11$, 3$2 random8shuffle, 11! remo#e, 116 remo#e8copy, 116

%TB containers, 43 de&ue, 47, ! map, 7 , 104, 22$ multimap, 7!, 107 multiset, 7! &ueue, 44, 430, 43! set, 71, 104 stac', 44 #ector, 4 , 4, 213, 34!, 0$ %TB iterators, 61 begin34, 62 const8iterator, 210 de*inin/ ran/es with, 62 end34, 63 iterator adapters, 6! bac'8insert8iterator, 6! bac'8inserter, 6$ front8insert8iterator, 66 front8inserter, 66 insert8iterator, 66 inserter, 66, 11$ istream8iterator, 66, 130, 213 istreambuf8iterator, 66, 203 ostream8iterator, 6!, 266 ostreambuf8iterator, 66 iterator cate/ories, 64 iterator, 61 re#erse8iterator, 64, 126 stream e4traction operator, 2 stream *ail#re, 32 stream insertion operator, 2

1 ?@E 1 stream manip#lators, 2$ boolalpha, 31 dec, 32 endl, 2$ he5, 32 left, 27 noboolalpha, 31 oct, 32 right, 27 setfill, 30 setw, 27, 31 stringstream, 3 , 130 synta4 s#/ar, 273 system, !4
O 0, 434 virt#al *#nction table, 443, 4$4

Inde4

F
( Iacro tric0, 1$3

0
=ero)overhead principle, 133
88=.%E88, 1!7 88?IJE88, 1!7 88JI@E88, 1!7 88%IUE88, 1!7 !" operator, $0, 1!! # (strin/i=in/ operator), 1!7 ## (to0en)pastin/ operator), 1$0 #define, 1 6

T
templates, 163 implicit inter*ace, 176 inte/er template ar/#ments, 336 template classes, 163 member *#nctions o*, 16 template *#nctions, 17 template member *#nctions, 177 o* template classes, 200 type in*erence, 17 , 364, 4$2 typename, 163, 200 temporary obAect synta4, 266, 346, 3!7 this, 247 and assi/nment operators, 2$1 and static member *#nctions, 2 1 as an invisible parameter, 2 0 throw, 373 lone throw statement, 37$ time, !!, 2 4 time8t, 2!! tolower, 117 try, 373 typedef, 71 typedef struct, 12

G
unary8function, 3$!

#nde*ined behavior, 143 #nion)*ind data str#ct#re, 22 using namespace std, 1$

K
#alarray, 313

Ni/enXre cipher, 2 #irtual, 434 in constr#ctors and destr#ctors, 447 virt#al destr#ctors, 441

dan/ers o*, 1 7 #elif, 1!2 #else, 1!2 #endif, 1!2 #if, 1!2 #ifdef, 1!3 #ifndef, 1!3 #include, 1 $ #undef, 1$3 2algorithm:, 113 2cassert:, 1$0 2cctype:, 116, 123 2cmath:, 123, 32 2comple5:, 42! 2cstddef:, 142 2cstdio:, 03 2cstdlib:, !4, !!, 1$2, 2 4 2cstring:, 147 2ctime:, !3, 2 4, 2!! 2fstream:, 2! 2functional:, 3$ implementation o*, 361 2iomanip:, 27 2iostream:, 1$ 2iterator:, 6! 2limits:, 3$3 2memory:, 376 2numeric:, 113 2sstream:, 3! 2stde5cept:, 374 2string:, 17 2utility:, 74 2#alarray:, 313

You might also like