Beruflich Dokumente
Kultur Dokumente
Com
The m at erial present ed here is not 100 % correct . There rem ain a num ber of fact ual
errors but I never t ried t o correct t hose. I f you are experienced program m er you can
easily figure out . St ill t his docum ent is very useful.
On e Sm a r t Click .Com
All im plem ent at ions im pose a lim it on t he num ber of files t hat a process can open
sim ult aneously. This lim it depends on various fact ors such as t he process’ privileges,
t he num ber of open files t hat ot her processes current ly use, and t he syst em ’s
resources. The const ant FOPEN_MAX which is defined in ( in C) is t he m inim um
num ber of files t hat t he im plem ent at ion guarant ees can be open sim ult aneously by a
single process. A process m ay occasionally succeed in opening a higher num ber of
files. However, t he syst em can guarant ee only up t o FOPEN_MAX open files per
process at any given t im e.
Esca pe Se qu e n ce s
\ a / * alert ( bell) * /
\ b / * backspace* /
\ f / * form feed* /
\ n / * new line* /
\ r / * carriage ret urn* /
\ t / * horizont al t ab* /
\ v / * vert ical t ab* /
\ \ / * backslash* /
\ ? / * quest ion m ark* /
\ ’ / * single quot e* /
\ " / * double quot e* /
To call a funct ion t hrough a point er, t reat t hat point er as if it were t he funct ion it self.
For exam ple:
# include
char buff[ 10] ;
void ( * pf) ( char * , const char * ) ;
pf= st rcpy; / * t ake address of st rcpy* /
pf( buff, "hi") ; / * call st rcpy via pf* /
The reason is t hat a const _it erat or isn’t really a const it erat or obj ect . I n fact , you can
alt er t he value of a const _it erat or, for exam ple, using + + . However, you cannot
change t he obj ect t o which a const _it erat or point s t hrough t hat it erat or. I f you t hink
of an it erat or as a point er t o T, a const _it erat or is not a T * const , but rat her, it ’s
const T * . I n t he following exam ple, t he const _it erat or’s value is increm ent ed.
However, t he at t em pt t o change a vect or’s elem ent t hrough t hat const _it erat or fails:
Tr e a t in g A Ve ct or As An Ar r a y
Suppose you have a vect or of int ’s and a funct ion t hat t akes int * . To obt ain t he
address of t he int ernal array of t he vect or v and pass it t o t he funct ion, use t he
expressions &v[ 0] or &* v.front ( ) . For exam ple:
I t ’s safe t o use &vi[ 0] and &* v.front ( ) as t he int ernal array’s address under t he
following rest rict ions. First , func( ) shouldn’t access out - of- range array elem ent s.
Second, t he elem ent s inside t he vect or m ust occupy cont iguous m em ory. Alt hough
t he C+ + St andard doesn’t guarant ee t hat yet , I ’m not aware of any im plem ent at ion
t hat doesn’t use cont iguous m em ory for vect ors. Furt herm ore, t his loophole in t he
C+ + St andard will be fixed soon.
I n m y previous t ip, I discussed t echniques for get t ing t he address of a vect or’s
int ernal array. Several im plem ent at ions now provide a nonst andard m em ber funct ion
of class vect or for t his purpose. This m em ber funct ion is called dat a( ) . As wit h
st ring: : dat a( ) , vect or: : dat a( ) ret urns a point er t o t he beginning of t he vect or’s
int ernal array. The C+ + st andardizat ion com m it t ee is reviewing suggest ions
regarding vect or’s cont iguit y. One of t he suggest ions is t o add t he dat a( ) m em ber
funct ion int o t he st andard. I t ’s t oo early t o predict whet her dat a( ) will event ually
m ake it int o t he st andard, so for t he t im e being, use &v[ 0] or &* v.front ( ) as port able
m et hods of get t ing t he address of a vect or’s int ernal array.
Com m a - Se pa r a t e d Ex pr e ssion s
The if condit ion cont ains t hree expressions separat ed by com m as. C+ + ensures t hat
each of t he expressions is evaluat ed and it s side effect s t ake place. However, t he
value of an ent ire com m a- separat ed expression is t he result of t he right m ost
expression. Therefore, t he if condit ion above evaluat es as t rue only if cin.good( )
ret urns t rue. Here’s anot her exam ple of a com m a expression:
int j = 10;
int i= 0;
while( + + i, - - j )
{
/ * ..repeat as long as j is not 0* /
}
BOOLEAN LI TERALS
The Boolean lit erals "false" and "t rue" evaluat e t o 0 and 1, respect ively. I n ot her
program m ing language, t rue and false m ay have different values. Visual Basic, for
inst ance, defines false as - 1 and t rue as 1. C+ + program m ers who writ e code t hat
int erfaces wit h ot her languages som et im es discover t his fact t he hard way.
Therefore, don’t assum e t hat "t rue" and "false" have t he sam e represent at ion in all
languages and environm ent s.
The associat ive cont ainers st d: : m ap, st d: : m ult im ap, st d: : set , and st d: : m ult iset have
t hree overloaded form s of t he m em ber funct ion earse( ) :
The first version t akes an it erat or point ing at an exist ing cont ainer elem ent and
erases it . For exam ple, t he following code erases t he last elem ent of t he cont ainer:
em ployees.erase( em ployees.rbegin( ) ) ;
An elem ent of an associat ive cont ainer is a pair of t wo values: a key and it s
associat ed value. The second version of erase( ) enables you t o erase an elem ent
using it s key. For exam ple:
The t hird version of erase( ) delet es a sequence of elem ent s whose bounds are
indicat ed by t he it erat ors first and last . For exam ple, t he following st at em ent erases
all t he elem ent s of a m ap:
Ca st in g Poin t e r s To M e m be r s
C+ + allows cast ing a point er t o m em ber t o anot her point er t o m em ber, as long as
t he signat ures of t he t wo m at ch. However, t he result s of such a cast are
im plem ent at ion- defined. You have t o consult your com piler’s m anual t o m ake sure
t hat such cast s are support ed. I f your code is t o be port ed t o several t arget
plat form s, you shouldn’t cast point ers t o m em bers at all.
Cr e a t in g A Te m por a r y File
FI LE * t m pfile( ) ;
I t opens a t em porary file for read/ writ e operat ions and ret urns a point er t o t hat file.
t m pfile( ) chooses unique filenam es t o avoid conflict s wit h any exist ing files. The
t em porary files creat ed by t m pnam e( ) are aut om at ically delet ed when t he program
t erm inat es.
Un in it ia lize d En u m Va r ia ble s
An aut om at ic uninit ialized enum variable has an indet erm inat e value. Uninit ialized
global and st at ic enum variables have a zero value by default . This m eans t hat such
an enum variable m ight have a value t hat is not in t he range of it s enum erat ors. I n
t he following exam ple, t he global enum variable st is default init ialized t o zero. This
bug leads t o unpredict able behavior at runt im e:
I t ’s best always t o init ialize enum variables explicit ly, t hereby avoiding such bugs:
St at st = good;
Pr iva t e M e m be r Fu n ct ion s
Privat e class m em bers represent im plem ent at ion det ails t hat shouldn’t be accessible
t o ot her classes and users. Your class m ay declare privat e m em ber funct ions as well.
For exam ple, suppose you have a m ult im edia player class whose public m em ber
funct ions play( ) , zoom ( ) and st op( ) , call int ernal m em ber funct ions, or helper
funct ions, t hat t ake care of int ernal operat ions such as m anaging m em ory buffers,
t hreads, and int erfaces t o sound and video cards. These int ernal operat ions are
highly specialized and access low- level hardware int erfaces. As such, t hey are likely
t o change wit h each new release or port t o anot her plat form . Therefore, t hey are
declared privat e so t hat ot her client s don’t use t hem direct ly.
The iost ream fam ily provides t he following m em ber funct ions and operat ors for
checking a st ream ’s st at e:
good( ) t akes all t he st ream ’s flags int o account , including eofbit , whereas fail( ) ,
operat or! ( ) , and operat or void* ( ) ignore eofbit . I f you want t o check whet her t he
st ream is in a st at e of error, use fail( ) , operat or! ( ) , or operat or void* ( ) . To check a
failure of input operat ions, call good( ) .
Absolu t e Va lu e s
The st andard funct ions abs( ) and labs( ) ( declared in < cst dlib > ) ret urn t he absolut e
value of int and long, respect ively. You can use t hese funct ions in com put at ions t hat
require absolut e values. For exam ple:
int begin= 0;
int end= 100;
int offset = abs( begin- end) ;
p is an "array of 10 point ers t o a funct ion ret urning void and t aking a point er t o
anot her funct ion t hat ret urns void and t akes no argum ent s," but t he cum bersom e
synt ax is nearly indecipherable. You can sim plify t his declarat ion considerably by
using t ypedefs. First , declare a t ypedef for "point er t o a funct ion ret urning void and
t aking no argum ent s" like t his:
Next , declare anot her t ypedef for "point er t o a funct ion ret urning void and t aking a
pfv":
The operat ors st at ic_cast and reint erpret _cast convert an operand’s t ype. However,
t hey aren’t int erchangeable; st at ic_cast uses t he t ype inform at ion available at
com pile t im e t o perform t he conversion, m aking t he necessary adj ust m ent s ( such as
point er offset calculat ion, t ype prom ot ion) bet ween t he source and t arget t ypes. I t s
operat ion, t herefore, is relat ively safe. On t he ot her hand, reint erpret _cast sim ply
reint erpret s t he bit pat t ern of a given obj ect wit hout changing it s binary
represent at ion. Consider t his exam ple:
int n= 9;
double d= st at ic_cast < double > ( n) ;
I n t his exam ple, we convert a variable of t ype int t o double. The binary
represent at ion of t hese t ypes is very different . To convert t he int 9 t o a double,
st at ic_cast needs t o properly pad t he addit ional byt es of d. As expect ed, t he result of
t he conversion is 9.0. reint erpret _cast ’s behavior is different :
int n= 9;
double d= reint erpret _cast ( n) ;
This t im e, t he result s are m eaningless. Aft er t he cast , d cont ains a garbage value.
This is because reint erpret _cast sim ply copied t he bit pat t ern of n int o d as is,
wit hout m aking t he necessary adj ust m ent s. For t his reason, you should use
reint erpret _cast sparingly and j udiciously.
A "com pound st at em ent " ( called a "block") is a sequence of one or m ore st at em ent s
enclosed bet ween { and } . For exam ple:
void func( )
{
/ / .. a com pound st at em ent
}
Suppose you need t o st ore obj ect s of different t ypes in t he sam e cont ainer. Usually
you do t his by st oring point ers t o dynam ically allocat ed obj ect s. I nst ead of using
nam ed point ers, insert t he elem ent s t o t he cont ainer as follows:
class Base { } ;
class Derived : public Base{ } ;
This way you ensure t hat t he st ored obj ect s can be accessed only t hrough t heir
cont ainer. You delet e t he allocat ed obj ect s as follows:
delet e v[ 0] ;
delet e v[ 1] ;
I t m ay be t em pt ing t o squeeze out an ext ra ounce of perform ance by rem oving all
debug inform at ion from an applicat ion’s release version. Even if an applicat ion seem s
st able at your sit e, m yst erious crashes- - due t o different set t ings, incom pat ible
libraries, different device drivers, and so on- - m ay occur when it ’s shipped t o a
cust om er. Therefore, m any developers recom m end leaving m inim al debugging info
even in t he release version so t hat t he runt im e environm ent can print t he call st ack
in a hum an- readable form at . Wit hout t his inform at ion, you won’t have any
inform at ion about t he cause of a crash.
Assign in g in t To An e n u m Va r ia ble
C+ + doesn’t allow you t o assign int eger value t o an enum erat ion direct ly:
You need t o use st at ic_cast t o explicit ly cast an int eger t o an enum erat ion:
I f t he int value is out side t he valid ranges of t he enum erat ion, t he result s are
undefined:
Fa ct or ia l Fu n ct ion
A fact orial funct ion is a classic exam ple of recursion. Here’s a t ypical recursive
fact orial funct ion:
fact orial( ) calls it self recursively, subt ract ing 1 from num on each call, unt il it equals
1. As always, you can use it erat ion inst ead of recursion:
Va r ia ble Le n gt h Ar r a ys
I n C89 and C+ + , an array’s size m ust be an int eger const ant expression so t hat it
can be com put ed at com pile t im e. I n C99, t he newly approved ANSI / I SO C st andard,
t his rule was relaxed - - you can now use any int eger expression t o define an array’s
size. For exam ple:
The num ber of elem ent s in arr m ay change every t im e func( ) is called. Therefore, it s
size can only be com put ed at runt im e. Such an array is called a variable lengt h
array:
int m ain( )
{
int dim ;
print f( "ent er array’s size: ") ;
scanf( "% d",&dim ) ;
func( dim ) ;
}
To support variable lengt h arrays, C99 changed t he sem ant ics of t he sizeof operat or.
Usually, sizeof expressions are evaluat ed at com pile t im e. However, when sizeof is
applied t o a variable lengt h array, t he result is evaluat ed at runt im e.
Rem em ber t hat variable lengt h arrays aren’t dynam ic arrays - - t hey can’t change
t heir size during t heir lifet im e. They differ from ordinary arrays in t hat t hey m ay
have a different size every t im e t hey are inst ant iat ed. Variable lengt h arrays can only
be local. Not e t hat st andard C+ + doesn’t support variable lengt h arrays. However,
because m any C+ + com pilers are also C com pilers, som e of t hem m ay support t his
feat ure as a nonst andard ext ension.
Ge n e r a t in g Un iqu e File n a m e s
To generat e a unique filenam e t hat won’t conflict wit h any ot her files in t he current
direct ory, use t he t m pnam ( ) funct ion declared in < cst dio > as follows:
The funct ion generat es a unique nam e t hat m ay cont ain up t o L_t m pnam charact ers.
You can call t m pnam ( ) up t o TMP_MAX t im es wit hout generat ing repeat ed nam es
( t he TMP_MAX and L_t m pnam const ant s are defined in ) . For exam ple:
Buffer overflows are a fert ile source of bugs and m alicious at t acks. They occur when
a program at t em pt s t o writ e dat a past t he end of a buffer. Consider t his exam ple:
Even if you can’t leverage legacy code wit h a m ore obj ect - orient ed approach, t here
are st ill som e t echniques t o avert such overflows. First , always check t he array’s
bounds before writ ing it t o a buffer. I f t his is im possible- - such as when t he input is
com ing from a CGI script - - use funct ions t hat explicit ly lim it t he num ber of input
charact ers. For exam ple, inst ead of using scanf( ) , use t he fget s( ) funct ion, which
reads charact ers up t o a specified lim it :
Addit ionally, t he st andard st ring funct ions have versions t hat t ake an explicit size
lim it . I nst ead of st rcpy( ) , st rcm p( ) , and sprint f( ) , use st rncpy( ) , st rncm p( ) , and
snprint ( ) , respect ively. Next t im e, we will see how t o avoid overflows using a m ore
obj ect - orient ed approach.
Re a din g I n pu t Sa fe ly
By using a st ring obj ect inst ead of a char array, you elim inat e t he risk of a buffer
overflow t hat m ight result from unchecked input :
st d: : st ring buff;
cout < < "ent er your nam e: "
cin > > buff;
Ca lcu la t in g Th e Pow e r Of Tw o N u m be r s
The St andard Library provides t he pow( ) funct ions ( declared in < cm at h ) , which
t akes t wo argum ent s of t ype double:
double x= 10, y= 4;
double result = pow( x, y) ; / * 10000* /
Le a r n in g Fr om Com pile r W a r n in gs
warning C4806: ’= = ’ : unsafe operat ion: no value of t ype ’bool’ prom ot ed t o t ype
’const long’ can equal t he given const ant .
This warning essent ially m eans t hat t he com piler cannot safely com pare a variable of
t ype bool and const long.
Wait a m inut e - - doesn’t t he expression above com pare a DWORD t o a long int ,
rat her t han bool vs. long int ? Act ually, it doesn’t , and t hat ’s exact ly t he problem .
The precedence of operat or = = is lower t han t he precedence of operat or! . Because
of t his, t he com piler parses t he expression as follows:
The warning m essage indicat es t hat som et hing bad is going on here and helps t he
program m er find t he bug. There are t wo lessons here: Never ignore com piler
warnings, and always parent hesize com plex expressions t o st at e operat ors’
precedence explicit ly.
Norm ally you don’t need t o im plem ent st ring com parison funct ions, because
st d: : st ring already does it . However, in som e applicat ions, you m ay have t o override
t he default com parison funct ionalit y. For exam ple, in Germ an, um laut ed charact ers
and t heir non- um laut ed count erpart s have t he sam e lexicographic rank, whereas
t heir ASCI I values differ.
You can short - circuit t he com parison process by first checking whet her t he t wo
st rings have t he sam e lengt h. Obviously, if t he lengt hs differ, t here’s no reason t o
cont inue t he com parison. Only if t he lengt hs are ident ical should you com pare t he
st rings charact er by charact er. Rem em ber t hat st ring: : lengt h( ) is a const ant t im e
operat ion t hat m erely ret urns a local variable. Therefore, t his t echnique can speed
your code, especially if you com pare long st rings.
class A
{
public:
A( int size) ;
privat e:
int size;
};
All of t hese form s are legal and port able. However, t he first one is preferable
because t he m em ber init ializat ion not at ion explicit ly indicat es t hat you’re init ializing
a dat a m em ber.
As for using ident ical nam es for t he dat a m em ber and t he argum ent , t he com piler is
clever enough t o dist inguish bet ween t he t wo correct ly. However, t o avoid confusing
a hum an reader, you m ay consider different nam es, as in
Funct ions defined inside a class body are im plicit ly inline. Therefore, t he inline
keyword is redundant here:
class Em ployee
{
public:
inline const st ring& nam e( ) const { ret urn _nam e; }
/ / ..
};
I n t his case, inline is harm less. However, it can becom e a m aint enance problem if
you m ove t he definit ion of nam e( ) out side t he class and ext end it wit h m ore
funct ionalit y ( for exam ple, if you convert t he st ring t o uppercase before ret urning it
t o t he caller) . Oft en program m ers forget t hat t he m em ber funct ion is st ill declared
inline, alt hough it was ext ended and m oved out side t he class body. Therefore, when
you define a m em ber funct ion inside it s class body, don’t declare it inline.
Block in g Fu r t h e r I n h e r it a n ce Of A Cla ss
To block a class from being derived any furt her, declare it s const ruct or privat e. Next ,
add a public st at ic m em ber funct ion I nst ance( ) t hat creat es an inst ance of t his class
and ret urns it s address. Calling I nst ance( ) is t he only way t o creat e inst ances of such
a class, because t he const ruct or is ot herwise inaccessible. Here’s an exam ple:
class A
{
privat e:
A( ) ;
public:
st at ic A* I nst ance( ) { ret urn new A; }
};
int m ain( )
{
A * pa = A: : I nst ance( ) ;
/ * ..use pa* /
delet e pa;
}
When you declare a nest ed class as a friend of it s cont aining class, place t he friend
declarat ion aft er t he declarat ion of t he nest ed class, not before it :
class A
{
privat e:
int i;
public:
class B / * nest ed class declared first * /
{
public:
B( A & a) { a.i= 0; } ; / * access A’s privat e m em ber* /
};
friend class B; / * friend declarat ion at t he right place* /
};
I f you place t he friend declarat ion before t he nest ed class’s declarat ion, t he com piler
will discard it since t he friend class has not been seen yet .
class A
{
privat e:
int n;
public:
int m ;
};
class B
{
privat e:
int n;
int m ;
};
The built - in + + and - - operat ors can appear on bot h sides of t heir operand:
int n= 0;
+ + n; / * prefix* /
n+ + ; / * post fix* /
You probably know t hat a prefix operat or first changes it s operand before t aking it s
value. For exam ple:
int n= 0, m = 0;
n = + + m ; / * first increm ent m , t hen assign it s value t o n* /
cout < < n < < m ; / * display 1 1* /
I n t his exam ple, n equals 1 aft er t he assignm ent because t he increm ent operat ion
t ook place before m ’s value was t aken and assigned t o n. By cont rast ,
int n= 0, m = 0;
n = m + + ; / * first assign m ’s value t o n, t hen increm ent m * /
cout < < n < < m ; / * display 0 1* /
I n t his exam ple, n equals 0 aft er t he assignm ent because t he increm ent operat ion
t ook place aft er m ’s original value was t aken and assigned t o n.
To bet t er underst and t he difference bet ween post fix and prefix operat ors, exam ine
t he disassem bly code generat ed for t hese operat ions. Even if you’re not fam iliar wit h
assem bly languages, you can im m ediat ely see t he difference bet ween t he t wo- -
sim ply not ice where t he inc ( increm ent ) assem bly direct ive appears:
Poin t e r Con u n dr u m s
Novices, especially t hose who have experience wit h garbage- collect ed languages, are
oft en confused wit h t he concept of obj ect deallocat ion and dest ruct ion in C+ + . They
t end t o invoke every obj ect ’s dest ruct or explicit ly or assum e t hat every point er m ust
be delet ed explicit ly.
However, in C+ + , t here is a sim ple rule: Only obj ect s t hat were allocat ed by new
m ust be dest royed using delet e. When working wit h arrays allocat ed by new[ ] , you
m ust use delet e[ ] .
When shouldn’t you use delet e? First of all, when you have aut om at ic and st at ic
obj ect s. Such obj ect s are dest royed aut om at ically; never at t em pt t o dest roy t hem
explicit ly. Furt herm ore, even if you have a point er assigned t o an obj ect , you
shouldn’t delet e it if it s bound obj ect wasn’t allocat ed by new. Here’s an exam ple:
void f( )
{
st ring s;
st ring * ps;
ps = &s;
}
Because s is a local aut om at ic obj ect , you shouldn’t delet e t he point er ps. The bound
obj ect s is dest royed aut om at ically when f( ) exit s. Rem em ber t hat delet ing any
obj ect t hat wasn’t allocat ed using new causes undefined behavior ( m ost likely, a
program crash) .
The st ack is a region of m em ory in which local aut om at ic variables are creat ed and
funct ion argum ent s are passed. The im plem ent at ion allocat es a default st ack size per
process. Modern operat ing syst em s allocat e a st ack size of at least 1 MB, which is
sufficient for m ost purposes. Under anom alous condit ions, t he program exceeds it s
st ack lim it , which causes a st ack overflow. The t wo m ost com m on causes for a st ack
overflow include an infinit e recursion, as in
int f( int n)
{
g( n) ;
}
int g( int n)
{
f( n) ;
}
Anot her com m on cause for st ack overflow is an at t em pt t o creat e a very large obj ect
on t he st ack, for exam ple:
int m ain( )
{
int n[ 10000000] ; / * array is t oo large * /
int j = 0; / * j ’s address exceeds t he st ack’s lim it s, error* /
}
I f your program crashes because of a st ack overflow, check for infinit e recursion or
t oo large aut om at ic obj ect s.
TH E FI LL( ) ALGORI TH M
The argum ent s f and l m ark t he sequence’s beginning and end, respect ively. fill( ) fills
t he elem ent s in t he sequence wit h t he fixed value T. This algorit hm is useful when
you want t o init ialize or reinit ialize a sequence wit h a fixed value. For exam ple, t o
init ialize a char array, use fill( ) as follows:
This is sim ilar t o calling m em set ( p, 0, 100) . Not e however, t hat fill( ) respect s obj ect
sem ant ics, unlike m em set ( ) . Therefore, you can use it t o reinit ialize a sequence of
obj ect s as well:
vs init ially cont ains 100 em pt y st rings. fill( ) assigns a new value: "greet ings! " t o all
t he st rings in t he vect or.
A nam espace alias can redefine an exist ing nam espace alias, as long as t he new
definit ion refers t o t he sam e nam espace as t he old one. I n ot her words, you’re
allowed t o repeat an exist ing definit ion of a nam espace alias, but you cannot change
t he m eaning of a previously defined nam espace alias. For exam ple:
This rule enables you t o place t he sam e nam espace alias definit ion in
every source file of t he sam e proj ect .
A Ge n e r ic Ca llba ck D ispa t ch e r
You can creat e a generic callback class t em plat e t o aut om at e m em ber funct ions’
callback. Such a t em plat e t akes t he class whose m em ber funct ion is t o be called as
it s first param et er. The second param et er is a point er t o t hat class’s m em ber
funct ion. The t rick is t hat you base t he second param et er on t he first one, as follows:
The im plem ent at ion of t he t em plat e is relat ively sim ple: I t has a reference t o T,
which is t he class whose m em ber funct ion is t o be called, a const ruct or and a
m em ber funct ion called execut e( ) :
To call a m em ber funct ion t hrough a point er t o m em ber, you m ust have a reference
or point er t o t he act ual obj ect . This is why t he t em plat e has a T& as a m em ber. Now
suppose you want t o use t he callback t em plat e t o execut e a m em ber funct ion of
class A:
class A
{
public:
void f( ) ;
};
You can’t use a variable as t he address of t he m em ber funct ion. I nst ead, use t he &
operat or t o t ake t he funct ion’s address. Finally, pass t he obj ect whose m em ber
funct ion you want t o be called as t he argum ent for t he t em plat e obj ect :
int m ain( )
{
A a; / * first , creat e an obj ect * /
callback < A, &A: : f > c( a) ; / * inst ant iat e t em plat e* /
c.execut e( ) ; / * invoke a.f( ) * /
}
You can use t he callback class t em plat e wit h any class t ype, as long as t he m em ber
funct ion called has t he sam e signat ure.
The .* and - > * operat ors enable you t o call a m em ber funct ion wit hout having t o
know t he funct ion’s nam e. Rem em ber t o parent hesize t he funct ion call as follows:
Alt hough som e com pilers accept it for an unknown reason, t his is not t he correct
C+ + synt ax.
Re t u r n in g Aggr e ga t e s Fr om A Fu n ct ion
A funct ion m ay ret urn class obj ect s, st ruct s, and unions by value. However, t he
runt im e overhead of ret urning large obj ect s by value can be significant . For
exam ple:
Under m any com pilers, t his form is m ore efficient t han t he previous one because it
elim inat es unnecessary const ruct ion and dest ruct ion of a t em porary obj ect .
For efficiency reasons, m ost im plem ent at ions use bit wise operat ors rat her t han
relat ional operat ors t o im plem ent t he st andard funct ions isalpha( ) , isdigit ( ) , isprint ( ) ,
and so on. Bit wise operat ions work well only when applied t o unsigned values.
However, on som e im plem ent at ions, char is signed by default . Consequent ly, t hese
funct ions m ay produce incorrect result s. To fix t his, explicit ly cast t he argum ent t o
unsigned char. This will ensure t hat t hese funct ions produce t he correct result s,
regardless of char’s signedness:
char c;
cout < < "ent er a charact er";
cin > > c;
bool alpha= isalpha ( ( unsigned char) c) ;
Use s Of Pr iva t e I n h e r it a n ce
Unlike public inherit ance, privat e inherit ance is useful when you want t o inherit t he
im plem ent at ion of a base class wit hout im plying an is- a relat ionship bet ween t hat
base class and it s descendant s. For exam ple, if A is a direct nonpublic base of B, B
has access t o all t he nonprivat e m em bers of A. However, B is not an A. I n t his
regard, privat e inherit ance is very close t o cont ainm ent . The m ain difference
bet ween t he t wo is t hat privat e inherit ance enables you t o access t he base’s
m em bers direct ly, as if t hey were m em bers of t he derived class.
Ar r a ys Of Lit e r a l St r in gs
I t shouldn’t . The st andard requires t hat t he size of a char array init ialized wit h a
lit eral st ring be sufficient ly large t o cont ain a t erm inat ing null. The declarat ion should
be flagged as a com pilat ion error because s has t hree elem ent s inst ead of four.
However, m any C+ + com pilers st ill follow t he array rules of C, which perm it char
arrays wit hout a t erm inat ing null.
N u ll Poin t e r Con st a n t s An d En u m e r a t or s
Here’s a t opic t hat was recent ly discussed at t he St andardizat ion com m it t ee.
Suppose we have t he following enum t ype:
I s it legal t o use t he enum erat or ’good’ as a null point er const ant ? Put different ly, is
t he following declarat ion legal?
void * p= good;
Aft er all, a null point er const ant in C+ + is eit her 0 or 0L and ’good’ equals 0. St ill,
t his declarat ion isn’t allowed because t he st andard says t hat "a null point er const ant
is an int egral const ant expression rvalue of int eger t ype t hat evaluat es t o zero." Let ’s
analyze it . A null point er const ant , e.g., NULL, 0, or 0L, m ust be an int egral const ant
expression. I ndeed, an enum erat or is an int egral const ant expression. However, t o
qualify as a null const ant expression, an ident ifier m ust also be an "rvalue of int eger
t ype." An enum erat or is an rvalue, but it isn’t an int eger t ype. Therefore, t he
declarat ion is illegal. There is anot her way t o reach t he sam e conclusion wit hout
split t ing hairs. C+ + allows only one im plicit conversion per expression. Therefore,
had we used a lit eral zero as t he init ializer of p
void * p= 0;
t he com piler would have im plicit ly convert ed t he lit eral zero t o t ype void * and
assigned it t o p. However, once we use ’good’ as an init ializer rat her t han zero, t wo
im plicit conversions are necessary. The first convert s t he enum erat or t o t he int eger
zero, and t he second convert s t he int eger zero t o void * . Because C+ + allows only
one im plicit conversion in t his cont ext , t he declarat ion is invalid.
The sam e rule applies t o user- defined obj ect s. You m ay bind a t em porary obj ect only
t o a const reference:
st ruct A{ } ;
void f( const A& a) ;
int m ain( )
{
f( A( ) ) ; / * OK, binding a t em porary A t o a const reference* /
}
Funct ions should only t hrow except ions t hat are list ed in t heir except ion
specificat ion. For exam ple:
class X{ } ;
class Y{ } ;
void f( ) t hrow ( X)
{
t hrow Y( ) ; / * violat ion of except ion specificat ion* /
}
Ge t t in g A Pr ogr a m ’s N a m e
The nam e of t he program ’s execut able file is st ored in argv[ 0] as a null- t erm inat ed
char array. To access it , declare m ain( ) as follows:
Even if t he applicat ion were called wit hout com m and- line argum ent s, C+ + ensures
t hat at least one argum ent , nam ely argv[ 0] , is passed t o m ain( ) . You can ext ract it
like t his:
People som et im es com plain about t he inaccuracy of float ing- point arit hm et ic. To
dem onst rat e t he level of float ing- point inaccuracy, consider t he following program :
On m y m achine, t his program print s 0.579956 inst ead of 0.58. More com plex
calculat ions yield higher inaccuracy. What is going on here? Rem em ber t hat
rounding, approxim at ion, and t runcat ion are not t he responsibilit y of C+ + . Rat her,
t hey depend on t he part icular hardware your m achine uses. Furt herm ore, float ing-
point num bers are m erely an approxim at ion based on t he I EEE st andard.
On m ost m achines, t ype float occupies 32 bit s, of which 1 bit will be used for t he
sign represent at ion, 8 bit s for exponent , and t he rem aining 23 bit s for t he m ant issa.
Because a m ant issa always has t he form 1.nnnn... t he leading 1 can be dropped so
t here are act ually 24 bit s allocat ed for t he m ant issa. 24- bit accuracy can have a
deviat ion of % 0.0000062 from t he original num ber. For higher accuracy, you can use
t he t ype double, which provides 53 bit s of m ant issa. This is m ore accurat e t han 24
bit s, but you can never get absolut e accuracy wit h bit s.
On m any im plem ent at ions, t he ANSI C library funct ions are in fact m acros in
disguise. m em set ( ) , m em cpy( ) , st rcpy( ) , and ot hers are oft en im plem ent ed as
m acros t hat invoke low- level syst em rout ines. While St andard C+ + st rict ly forbids
t his m acro- in- disguise t rick, it is st ill widely used in C. Beware of passing argum ent s
wit h a side effect t o such pseudo- funct ions. The result s in t his case m ight be
undefined. To see t he pot ent ial dangers of passing an argum ent wit h a side effect t o
a m acro in disguise, consider t his exam ple:
I f m em set ( ) happens t o be a m acro t hat passes it s argum ent s t o anot her funct ion,
n’s value is increm ent ed t wice before it s usage.
D yn a m ic Type An d St a t ic Type
The t ype of t he m ost derived obj ect t o which an expression refers is said t o be t he
dynam ic t ype of t hat expression. For exam ple, if p is declared as a point er t o class B
but it act ually point s t o an obj ect of class D ( where D is derived from B) , t he
dynam ic t ype of t he expression * p is D whereas it s st at ic t ype is B:
B * p; / * st at ic t ype of * p is B* /
p = new B; / * dynam ic t ype of * p is D* /
A sm all num ber of funct ions from t he St andard Library have different signat ures in C
and C+ + . These funct ions are: st rchr( ) , st rpbrk( ) , st rrchr( ) , st rst r( ) , and m em chr( )
as well as t heir wide- charact er count erpart s: wcschr( ) , wcspbrk( ) , wcsrchr( ) ,
wcsst r( ) , and wm em chr( ) . They are declared in t he st andard header ( or < cst ring >
in C+ + ) . Let ’s look at st rst r( ) . While in C, st rst r( ) has t he following prot ot ype:
I n C+ + , t his funct ion has t wo different prot ot ypes t hat are incom pat ible wit h t he C
version:
Anot her exam ple: t he funct ion st rpbrk( ) . I n C, it has t his signat ure:
Can you see t he pat t ern here? The C funct ion t akes "const X * " and ret urns "X * "
whereas C+ + defines t wo funct ions, one t aking "X * " and ret urning "X * ", and
anot her t aking "const X * " and ret urning "const X * ". Pay at t ent ion t o t hese subt le
differences when you port code from C t o C+ + or vice versa.
Con st a n t Ex pr e ssion s
C+ + requires t he use of int egral const ant expressions in various cont ext s; for
exam ple, when you define arrays’ sizes, case labels, bit - field sizes, and enum erat or
init ializers. An int egral const ant expression is one of t he following:
x < 100;
* Const variables or st at ic dat a m em bers of int egral or enum erat ion t ypes init ialized
wit h const ant expressions- - for exam ple, x in t his definit ion:
const int x = 0;
* Non- t ype t em plat e param et ers of int egral or enum erat ion t ypes:
sizeof ( int ) ;
Re cu r sion : M yt h An d Re a lit y
CS sophom ores learn t hat recursion can neat ly solve com plex problem s such as
wildcards handling and code parsing. I n pract ice, t hough, recursion oft en com plicat es
m at t ers unnecessarily. Every recursion- based algorit hm can be expressed as an
it erat ive one. I t erat ion is m ore com m on and int uit ive t o m ost program m ers t han
recursion. Addit ionally, it ’s m ore efficient because it avoids t he overhead of recurrent
funct ion calls ( recursive calls usually aren’t inlined, eit her) . Furt herm ore, while you
can have a loop t hat execut es infinit ely, every operat ing syst em lim it s t he num ber of
possible recursive calls. The lim it depends on available st ack m em ory. Thus, t he
behavior of program s wit h m any recursive calls m ight be unpredict able if t he dept h
of recursion exceeds t hat st ack’s lim it . Recursion is cut e and can im press your
college inst ruct or. However, in real- world program m ing, you should use it sparingly.
Type Qu a lifie r s’ Or de r
Com pu t in g Th e M a x im u m Of Th r e e Va lu e s
The st d: : m ax( ) t em plat e t akes t wo values and ret urns t he highest . What if you need
t o calculat e t he m axim um of t hree values? Don’t writ e a special funct ion t em plat e for
t his purpose. I nst ead, apply m ax( ) t o t wo arbit rary values of t he t hree, and t hen
apply m ax( ) once again t o t he result and t he t hird value:
Here’s a com m on error: You define a class- int ernal t ype, say an enum or t ypedef,
and t hen t ry t o use it as t he ret urn t ype of t hat class’s m em ber funct ion:
class A
{
public:
enum sizes { sm all, m edium , large} ;
sizes default _size( ) const { ret urn m edium ; }
};
Up unt il now, all is fine. However, at a lat er st age you decide t o m ove t he body of
default _size( ) out side t he class:
All of a sudden, t he com piler is barking at you t hat sizes is an unknown t ype. The
problem is t hat out side t he scope of class, you m ust use a qualified nam e t o refer t o
an int ernal t ype, as follows:
The com piler recognizes t he nonqualified nam es defined wit hin a class only wit hin
t hat class’s scope. Elsewhere, you need t o use it s qualified nam e.
Fa st e st M in im u m - W idt h I n t e ge r s
The header < int t ypes.h > , which was first available as a nonst andard ext ension,
recent ly becam e an int egral part of C99. I t defines a set of t ypedef nam es called
"fast est m inim um - widt h int eger t ypes." Each of t hese nam es designat es an int eger
t ype t hat is usually fast est t o operat e wit h am ong all int eger t ypes t hat have at least
t he specified widt h. These int egers have t he general form of int _fast n_t or
uint _fast n_t , where n is t he m inim um required widt h. For inst ance, int _fast 32_t is
t he fast est signed int eger t ype having a widt h of at least 32 bit s. The fast est
m inim um - widt h int eger t ypes are
What are t hey good for? Suppose you need a loop count er t hat needs no fewer t han
16 bit s. Ost ensibly, you can use a variable of t ype short . However, under cert ain
RI SC archit ect ure, t he use of short is less efficient t han int . To m ake sure t hat t he
count er’s t ype is always t he one wit h which t he CPU operat es opt im ally, use
int _fast 16_t inst ead of short . This way, you ensure t hat on every plat form , t he
com piler uses t he fast est int egral t ype t hat has at least 16 bit s:
D e le t in g M u lt idim e n sion a l Ar r a ys
You can allocat e a m ult idim ensional array using new as follows:
class A
{
public:
int j ;
/ * const ruct o, dest ruct or...* /
}
int m ;
A ( * pa) [ 2] [ 2] = new A[ 2] [ 2] [ 2] ; / * t hree dim ensional array* /
m = pa[ 0] [ 0] [ 0] .j ; / * access m em ber of array’s first elem ent * /
m = pa[ 1] [ 1] [ 1] .j ; / * access m em ber of array’s last elem ent * /
The program allocat es a t hree- dim ensional array of A’s called pa. How do you delet e
a dynam ically allocat ed m ult idim ensional array? I t ’s sim ple: No m at t er how m any
dim ensions t he array has, you always use delet e[ ] t o dest roy it :
delet e[ ] pa;
Pla ce m e n t D e le t e
Advanced program m ers are fam iliar wit h t he concept of placem ent new, which
creat es an obj ect on a predet erm ined m em ory posit ion. C+ + defines a placem ent
version of operat or delet e, t oo. Unlike wit h placem ent new, you’re not supposed t o
call placem ent delet e direct ly. Placem ent delet e m erely serves as t he deallocat ion
funct ion t hat t he im plem ent at ion invokes when an except ion occurs during t he
const ruct ion of an obj ect by placem ent new.
The general rule is t hat for every version of operat or new, C+ + provides a m at ching
operat or delet e t o be invoked in t he event of an except ion. For inst ance, if an
except ion occurs during t he execut ion of new [ ] , C+ + invokes delet e [ ] . Likewise,
when an except ion occurs during t he execut ion of placem ent new, placem ent delet e
is invoked.
As opposed t o a com m on belief, placem ent delet e does not invoke t he dest ruct or of
it s argum ent ; in fact , it has no effect . To ensure t hat an obj ect const ruct ed by
placem ent new is dest ruct ed, you st ill need t o call it s dest ruct or explicit ly.
M u lt idim e n sion a l Ar r a ys
However, t his st yle is t edious and error prone. You m ust parent hesize ppi t o ensure
t hat t he com piler parses t he declarat ion correct ly, and you m ust delet e t he allocat ed
m em ory. Worse yet , you can easily bum p int o buffer overflows. Using a vect or of
vect ors t o sim ulat e a m ult idim ensional array is a m uch bet t er alt ernat ive:
Because vect or overloads operat or [ ] , you can use t he [ ] [ ] not at ion as if you were
using a built - in t wo- dim ensional array:
The soft ware indust ry uses t he t erm I 18N as an abbreviat ion for
"int ernat ionalizat ion." The idea is t hat I 18N begins wit h an i, ends wit h an n, and has
18 charact ers in bet ween. This way, one avoids t he unwieldy t erm and it s different
spelling convent ions ( int ernat ionalisat ion in Brit ish English) . Likewise, "localizat ion" is
abbreviat ed t o L10N. When you’re consult ing your com piler’s online help or run a
query on a search engine regarding int ernat ionalizat ion and localizat ion of C+ + apps,
t ry t hese abbreviat ions.
A st at ic m em ber funct ion doesn’t t ake an im plicit "t his." Therefore, it can’t access
any ot her m em bers of it s class unless t hey are also st at ic. Som et im es you have no
choice but t o use a st at ic m em ber funct ion, but you st ill need t o access ot her
m em bers of t he class from t hat funct ion. There are t wo solut ions. One solut ion is t o
declare t hese m em bers st at ic, so t hat t he st at ic m em ber funct ion can access t hem
direct ly. For exam ple:
class Singlet on
{
public:
st at ic Singlet on * inst ance( ) ;
privat e:
Singlet on * p;
st at ic Lock lock;
};
Alt ernat ively, pass t he st at ic m em ber funct ion a reference t o t he obj ect so t hat it can
access it s m em bers:
Alt hough t he St andard Library doesn’t define funct ions t hat convert Fahrenheit
degrees t o Celsius degrees and vice versa, you can im plem ent t hem by yourself.
These funct ions are part icularly useful in localizat ion and int ernat ionalizat ion
proj ect s. You m ay also find t hem useful in any int ernat ional weat her report Web sit e.
Here are t he t wo conversion funct ions:
N u m e r ic Lim it s
To find out t he m axim um num ber of decim al digit s of a cert ain num eric t ype, use t he
st andard t em plat e st d: : num eric_lim it s ( defined in < lim it s > ) . I t s digit s10 const ant
holds t he im plem ent at ion- dependent num ber of m axim um decim al digit s of every
built - in t ype:
Ex t e r n Fu n ct ion s
Unless explicit ly declared st at ic, an ordinary funct ion is im plicit ly declared ext ern. For
exam ple:
However, som et im es t he ext ern qualifier is added t o a funct ion declarat ion t o
docum ent t he fact t hat it has ext ernal linkage and can be called from any t ranslat ion
unit - - for exam ple:
Do not confuse plain ext ern wit h ext ern "C". ext ern "C" indicat es t hat an ident ifier
has C linkage rat her t han C+ + linkage, whereas plain ext ern m erely guarant ees t hat
t he ident ifier is globally visible.
The overloaded operat or m echanism is "synt act ic sugar" for ordinary funct ion calls.
You can always use t he explicit nam e of an overloaded operat or t o resolve
am biguit ies and docum ent your int ent ion explicit ly. For exam ple, t he st at em ent
I nst ead of using t he operat or’s sign direct ly, you can use a com binat ion of t he
keyword ’operat or’ followed by t he operat or’s sign and it s argum ent list . Anot her
exam ple: I nst ead of writ ing
st ring s;
bool em pt y;
em pt y = ( s= = "") ;
Alt hough you wouldn’t norm ally use t his unwieldy form , you should be fam iliar wit h
t his not at ion because som e com pilers and linkers issue error m essages t hat cont ain
t he explicit operat or funct ion nam e.
Copyin g File s
To copy t he cont ent s of one file int o anot her, use t he fst ream classes. First , open t he
source file using an ifst ream obj ect , t hen creat e a t arget file using ofst ream , and
finally, read t he source int o t he t arget using t he rdbuf( ) m em ber funct ion:
Not e t hat you don’t have t o call t he close( ) m em ber funct ion because t he fst ream
obj ect s do t hat aut om at ically when t heir dest ruct ors are invoked. However, you want
t o call close( ) if ot her part s of t he program access t he files before t he fst ream
obj ect s go out of scope.
Many program m ers believe t hat by st oring point ers inst ead of obj ect s in a cont ainer,
t hey im prove perform ance. However, t hey forget t hat t he point ers st ill refer t o
exist ing obj ect s t hat m ust be st ored som ewhere. Worse yet , t hese obj ect s are oft en
allocat ed dynam ically. Dynam ic allocat ion is an expensive operat ion. Rem em ber also
t hat you have t o delet e t hese obj ect s as well, which incur m ore runt im e overhead.
Perhaps t he m ost com pelling argum ent against t he use of point ers as cont ainer
elem ent s is t hat you can easily avoid t he overhead associat ed wit h m oving obj ect s in
m em ory by pre- allocat ing enough st orage for t he cont ainer in advance. This will
ensure t hat no reallocat ion t akes place- - hence, no obj ect s are m oved inside t he
cont ainer. You can pre- allocat e st orage by calling t he reserve( ) m em ber funct ion:
I n m ost cases, an em pirical t est will show t hat t he overall perform ance of obj ect
cont ainers is superior t o t he perform ance of point er cont ainers. Furt herm ore,
avoiding t he use of point ers, dynam ic allocat ion, and deallocat ion reduces t he
num ber of pot ent ial bugs dram at ically. The only except ion t o t his rule is when you
want t o st ore obj ect s of different t ypes in t he sam e cont ainer. I n t his case, you have
no choice but t o use a cont ainer of point ers.
H ow To Un do A M a cr o
I f you happen t o define an obj ect , funct ion, or const ant whose nam e collides wit h a
m acro locat ed elsewhere in a t hird- part y header file, as in
/ * file defs.h * /
/ * ...m any declarat ion* /
# define PI 3.14
/ * your program : * /
# include "defs.h"
const double PI = 3.141592653; / * error, ’PI ’ redefined* /
# include "defs.h"
# undef PI / * from now on, ignore t he PI m acro* /
const double PI = 3.14159265358979 / * OK* /
The post fix operat ors + + and - - are less efficient t han t heir prefix count erpart s
because t he com piler usually creat es a t em porary copy of t he operand before
applying t he operat or t o it . When using fundam ent al t ypes such as int or char, m ost
com pilers can opt im ize t he code and elim inat e t his perform ance overhead.
Therefore, t here’s no real difference bet ween t hese expressions:
for ( int j = 0; j
for ( int j = 0; j
However, wit h user- defined t ypes, m ost com pilers can’t opt im ize t he post fix version.
Consider:
Therefore, always prefer prefix operat ors t o post fix ones when you can choose
bet ween t he t wo.
x= x+ 5;
x= x/ 5;
x= x* 5;
C+ + defines short er versions t hat elim inat e t he need t o repeat t he variable’s nam e
t wice:
x+ = 5; / * equivalent t o x= x+ 5* /
x/ = 5; / * equivalent t o x= x/ 5* /
x* = 5; / * equivalent t o x= x* 5* /
The short hand versions are m ore convenient since t hey save a few keyst rokes. I n
addit ion, t hey m inim ize t he chance of m aking t ypos in variables wit h long nam es.
M e m cpy( ) Ca ve a t s
m em cpy( ) copies POD ( plain old dat a) t ypes, but not class obj ect s. For copying
obj ect s, use t he st d: : copy( ) algorit hm . Rem em ber also t hat t he point ers passed t o
m em cpy( ) m ust point t o nonoverlapping addresses; ot herwise, t he result s are
undefined. For exam ple:
st ruct A
{
int n;
};
A a;
m em cpy( &a, &a, sizeof( A) ) ; / * overlapping point ers; undefined* /
Generally speaking, t he ort hodox approach of dedicat ing a separat e .cpp and .h file
for every class is t he way t o go. However, in real- world program m ing you soon find
yourself recom piling every app for hours j ust because you added anot her dat a
m em ber t o a class. Here are t wo t echniques for reducing build t im e.
First , group several relat ed classes in a single .h file. Sim ilarly, im plem ent t hese
classes in a single .cpp file. Two derived classes can usually be considered relat ed- -
t hat is, a fam ily of except ion classes. Likewise, classes t hat depend on one anot her
or classes t hat part icipat e in a single t ask are relat ed classes. Declaring such classes
in a single .h file and im plem ent ing t hem in a single .cpp file reduces t he overall
build t im e and sim plifies m aint enance. Not e t hat wit h every # include direct ive, t im e
is wast ed on accessing t he physical file, opening it , and reading it s cont ent . Thus, by
reducing t he num ber of separat e physical files you also reduce t he t ot al build t im e.
Several com pilers support increm ent al com pilat ion and link feat ures, precom piled
and cached headers. Enabling t hese feat ures also reduces build t im e considerably.
Consult your com piler’s m anual for furt her inform at ion.
When an except ion is t hrown and no m at ching handler can be found for it , C+ + calls
t he funct ion t erm inat e( ) . By default , t erm inat e( ) invokes t he funct ion abort ( ) . Som e
com pilers guarant ee t hat at t his point , t he st ack has been unwound, m eaning all
local aut om at ic obj ect s have been fully dest ruct ed, st ream s have been flushed, and
open files have been closed. Ot her com pilers don’t unwind t he st ack in t his case,
t hough. Whet her t he st ack is unwound in t he case of an uncaught except ion is
plat form - defined. Therefore, you should check your com piler’s docum ent at ion t o
know how it behaves in t he event of an uncaught except ion.
Count ing t he num ber of inst ances of a cert ain class is oft en necessary in debugging
and perform ance t uning. To do t hat , declare a st at ic dat a m em ber as a count er, and
have t he const ruct or and copy const ruct or increm ent it and t he dest ruct or decrem ent
it . Finally, add a st at ic m em ber funct ion t hat ret urns t he count er’s value:
class A
{
privat e:
st at ic int count ;
public:
A( ) { + + count ; }
A( const A& rhs) { + + count ; }
~ A( ) { - - count ; }
public:
st at ic int get _count ( ) { ret urn count ; }
};
Because st at ic m em bers are aut om at ically zero- init ialized, you can call t his funct ion
and get t he correct result s even if no inst ance of t hat class exist s:
int m ain( )
{
int n = A: : get _count ( ) ; / / 0
A a;
n = A: : get _count ( ) ; / / 1
A * p = new A( a) ;
n = A: : get _count ( ) ; / / 2
delet e p;
n = A: : get _count ( ) ; / / 1
}
N on - Bu ffe r e d St r e a m s
The st andard st ream obj ect st d: : cerr and it s m at ching wide- charact er version,
st d: : wcerr, are non- buffered. This m eans t hat t hey are aut om at ically flushed aft er
each operat ion. This feat ure is part icularly useful for error report ing because it
ensures t hat if t he program crashes because of an error, t he st ream ’s dat a isn’t lost .
Not e t hat because t hese st ream s aren’t buffered, using t he endl m anipulat or is never
needed:
I n a previous t ip, I showed you how t o swap t wo variables wit hout using a t em porary
variable. There’s anot her version of t his solut ion t hat applies t o int egral values only.
Here it is:
You can apply t his t echnique t o any int egral t ype- - such as char, short , unsigned
long- - but not t o float ing- point variables. Not e t hat t he classic im plem ent at ion of
swap:
t em p = i;
i = j;
j = t em p;
is st ill t he m ost efficient one. I t ’s also m ore generic because it can be used wit h any
t ype t hat support s assignm ent .
STL cont ainers and algorit hm s require t hat you overload operat or < for t he class
t ype t hey st ore as elem ent s. This is necessary for sort ing and com paring t hese
elem ent s. STL synt hesizes t he equalit y operat or from t he < operat or by using t he
following const ruct :
Re n a m in g A File
To renam e a file, use t he st andard funct ion renam e( ) ( declared in ) . This funct ion
t akes t wo argum ent s of t ype const char * - - t he first is t he old nam e and t he second
is t he new nam e of t he file:
On success, renam e( ) ret urns zero; ot herwise, it ret urns a code indicat ing t he error
t ype.
The st andard st ream obj ect s support all t he built - in t ypes of C+ + and several ot her
classes defined in t he St andard library, such as st d: : st ring. I f you’re using com plex
arit hm et ic, you’ll be pleased t o hear t hat C+ + also st ream s support obj ect s of t ype
com plex:
int m ain( )
{
com plex < double > num ( 0.5, 0.0) ;
cout < < "num is: " < < num < < endl;
cout < < "ent er a new com plex value: ";
cin > > num ;
cout < < "value ent ered is: " < < num < < endl;
}
Th e St u ff I n A Libr a r y
A library is essent ially a file t hat cont ains com piled obj ect m odules ( a m odule is an
obj ect file produced from com piling a single source file) . A program can call, or
im port , rout ines and access dat a defined in anot her library. Such libraries can
cont ain t he St andard library, t hird- part y num eric analysis funct ions, m ult im edia
packages, graphics, et c. The t wo m ain cat egories of libraries are st at ic libraries and
dynam ic libraries. When you link your code wit h a st at ic library, t he program copies
t he code and dat a it needs from t hat library int o t he execut able file. Thus, a st at ically
linked program t hat calls print f( ) cont ains a copy of t his funct ion in it s execut able
file. By cont rast , a dynam ic library ( also called a runt im e library) is linked t o a
program at runt im e: References t o funct ions and dat a from t he runt im e library are
resolved at runt im e and are not copied int o t he program ’s execut able file.
Most im plem ent at ions provide a runt im e library t hat cont ains t he st andard funct ions
and dat a st ruct ures of C/ C+ + such as t he print f( ) funct ion, operat or new and delet e,
iost ream obj ect s, et c. A runt im e library is usually shared- - all processes and
applicat ions share a single copy of t hat library inst ead of having m ult iple copies
t hereof. A runt im e library offers t hree advant ages com pared t o a st at ically linked
one:
That said, dynam ic libraries can also cause serious difficult ies if several applicat ions
depend on t he sam e library and t he library is changed behind t heir back. This
problem is known as "D LL h e ll" in Windows, alt hough ot her plat form s suffer from it ,
t oo. Addit ionally, dynam ic linking incurs ext ra overhead in t erm s of runt im e speed
and m em ory.
On each it erat ion, it invokes t he funct ion st rlen( ) . You can im prove t his loop’s
perform ance by caching t he result of st rlen( ) and using t he cached value in t he loop:
Usin g D YN AM I C_ CAST
You can apply operat or dynam ic_cast only t o polym orphic obj ect s or point ers of such
obj ect s ( a polym orphic obj ect is one t hat has at least one virt ual m em ber funct ion,
including inherit ed virt ual funct ions) . There are t wo reasons for t his rest rict ion. To
perform a dynam ic cast , t he im plem ent at ion needs t o access t he runt im e t ype
inform at ion of t he obj ect t o which dynam ic_cast is applied. This inform at ion is
ret rieved t hrough t he obj ect ’s vpt r. As you probably know, only polym orphic obj ect s
have a vpt r. There’s anot her reason for t his rest rict ion, t hough- - a philosophical one.
The t ype of a nonpolym orphic obj ect is st at ic and can be det erm ined at com pile t im e.
Therefore, t here’s no reason t o use dynam ic_cast in t he first place.
Floa t in g- Poin t Ar it h m e t ic M yt h s
I n t he olden days, t he use of float ing- point variables im posed significant com put at ion
and speed overhead com pared t o int eger arit hm et ic. For t his reason, m any
opt im izat ion guidebooks and I T vet erans st ill use int egers inst ead of float ing- point
dat a. However, on som e m odern processors ( such as Pent ium ) , float ing t ype
arit hm et ic is FASTER t han int eger arit hm et ic. Therefore, if you want t o accelerat e a
com put at ion- int ensive applicat ion on such plat form s, you should reverse t his rule:
Use float ing- point dat a inst ead of int egers. Don’t get m e wrong here- - I don’t
recom m end using float ing point inst ead of int egers as loop count ers, for exam ple.
The lesson here is t hat you should experim ent before applying any opt im izat ion
m easures- - som e of t hem m ight t urn out t o be count erproduct ive.
The size of class can be changed sim ply by playing wit h t he order of it s m em bers’
declarat ion:
st ruct A
{
bool a;
int b;
bool c;
} ; / * sizeof ( A) = = 12* /
On m y m achine, sizeof ( A) equals 12. This result m ight seem surprising because t he
t ot al size of A’s m em bers is only 6 byt es: 1 + 4 + 1 byt es. Where did t he rem aining
6 byt es com e from ? The com piler insert ed 3 padding byt es aft er each bool m em ber
t o m ake it align on a 4- byt e boundary. You can reduce A’s size by reorganizing it s
dat a m em bers as follows:
st ruct B
{
bool a;
bool c;
int b;
} ; / / sizeof ( B) = = 8
This t im e, t he com piler insert ed only 2 padding byt es aft er t he m em ber c. Because b
occupies 4 byt es, it nat urally aligns on a word boundary wit hout necessit at ing
addit ional padding byt es.
As a rule, group dat a m em bers t hat occupy less t han t he size of t he nat ive alignm ent
boundary t oget her so t hat t heir t ot al size of t he alignm ent boundary is as sm all as
possible ( preferably zero) .
Each specializat ion of Vect or has t he specializat ion C < void* > as a friend. However,
all ot her specializat ions of C, such as C < int > , are not friends of Vect or.
Ordinary ( t hat is, non- t em plat e) funct ions and classes can be friends of a class
t em plat e. I n t he following exam ple, t he class t em plat e Vect or declares t he funct ion
f( ) and class Thing as it s friends:
f( ) and class Thing are friends of each specializat ion of Vect or.
Use s Of Re ve r se I t e r a t or s
Reverse it erat ors are ordinary it erat ors except t hat t hey invert t he sem ant ics of t he
overloaded + + and - - operat ors. Thus, applying + + t o a reverse it erat or posit ions it
one elem ent away from t he sequence’s end. Reverse it erat ors are useful when you
access elem ent s in a reverse order. For exam ple:
The m em ber funct ions rbegin( ) and rend( ) - - reverse begin( ) and reverse end( ) - - are
sim ilar t o begin( ) and end( ) except t hat t hey ret urn reverse it erat ors.
Th e fin d( ) Algor it h m
The algorit hm st d: : find( ) locat es an elem ent in a sequence. find( ) t akes t wo it erat ors
t hat point t o t he beginning and t he end of t he sequence, respect ively. The t hird
argum ent is t he sought - aft er value. find( ) ret urns an it erat or point ing t o t he first
elem ent in t he sequence t hat is ident ical t o t he sought - aft er value. I f find( ) cannot
locat e t he request ed value, it ret urns an it erat or point ing one elem ent past t he final
elem ent in t he sequence ( t hat is, it ret urns t he sam e value as does end( ) ) . For
exam ple:
list < char > : : it erat or p = find( lc.begin( ) , lc.end( ) , ’A’) ; / * find
’A’ in list * /
if ( p ! = lc.end( ) ) / * was A found?* /
* p = ’S’; / * if so, replace it wit h ’S’* /
while ( p ! = lc.end( ) ) / * display m odified list * /
cout < < * p+ + ;
}
St a n da r d Ex ce pt ion s
C+ + defines a hierarchy of st andard except ions t hat are t hrown at runt im e when
abnorm al condit ions arise- - for exam ple, when operat or new fails. The st andard
except ion classes are derived from st d: : except ion class ( defined in t he st andard
header < st dexcept > ) . This hierarchy enables you t o handle st andard except ions in
a uniform fashion:
The st andard except ions t hrown by built - in operat ors of t he language are
Not e t hat t he St andard library has an addit ional set of except ions t hrown by it s
com ponent s.
A funct ion can specify explicit ly what t ype of except ion it m ight t hrow by proving an
except ion specificat ion. Except ion specificat ions are enforced at runt im e. Therefore,
t he following code is perfect ly legal:
{
int result = f( ) ; / * what if f( ) t hrows?* /
}
g( ) prom ises not t o t hrow. However, it calls f( ) , which m ight t hrow any t ype of
except ion. I f f( ) indeed t hrows, t he except ion propagat es t hrough g( ) , t hereby
violat ing it s guarant ee not t o t hrow. St ill, t he com piler doesn’t rej ect t his code
because C+ + enforces except ion specificat ion at runt im e.
There are several reasons for t he runt im e checking policy. I n t his exam ple, f( ) could
be a legacy C funct ion. I t ’s im possible t o enforce a C funct ion t o have an except ion
specificat ion. For t his reason and ot hers, C+ + except ion specificat ions are enforced
at runt im e.
A global funct ion m ay be declared inline. I f you use t he sam e funct ion in different
developm ent environm ent s, such as C and C+ + , you can hide t he "inline" keyword
from a C com piler while keeping it visible t o a C+ + com piler, like t his:
# ifndef __cplusplus
# define inline
# endif
The preprocessor direct ives m ake sure t hat only a C+ + com piler sees t he inline
keyword:
inline int get _dst ( ) { ret urn dst ; } / / inline not seen by C
Not e t hat t he new C99 st andard support s inline. Therefore, fut ure C com pilers won’t
need t his hack.
Assign in g I n t e ge r s To En u m Va r ia ble s
C and C+ + differ in t heir handling of enum t ypes. While C allows you t o assign a
plain int t o an enum variable, C+ + doesn’t . Therefore, a C com piler will accept t he
following code while a st andard com pliant C+ + com piler won’t :
C+ + has st rict er t ype safet y rules. A st andard- com pliant C+ + com piler will rej ect t he
assignm ent of 1 t o d. You have t o use an explicit cast for t his t o work, or bet t er st ill,
always assign an enum erat or t o an enum variable:
Som e program m ers use a t ype field t o dist inguish bet ween slight ly different t ypes of
obj ect s. A classic exam ple is class Em ployee t hat has a t ype field indicat ing t he
Em ployee’s cat egory, such as t em porary or execut ive. A m ore realist ic exam ple is a
credit card class t hat has a t ype field indicat ing a credit card’s t ype. Oft en, derivat ion
is a bet t er design approach. I nst ead of using a single credit card class wit h a t ype
field, you can derive dist inct credit card classes- - Visa, MC, Swit ch, et c.- - from a
com m on base class. This design approach enables you t o express slight variat ions
t hat exist am ong credit card com panies. For inst ance, som e cards carry t he owner’s
pict ure on t he back. Ot hers also serve as ATM cards, and som e have an issue
num ber. Using inherit ance inst ead of t ype fields t o represent t hese differences
im proves fut ure m aint enance and debugging, and is a m ore obj ect - orient ed
approach.
En h a n cin g Ve ct or ’s Pe r for m a n ce
st d: : vect or allocat es st orage for it s elem ent s on dem and. This is advant ageous
because it frees you from t he hassles of m anual m em ory m anagem ent . However, in
real- t im e environm ent s, frequent reallocat ion of m em ory can incur unaccept able
overhead. I f you know t he t ot al num ber of elem ent s t hat are t o be st ored in
advance, you can preallocat e st orage for t hem at once using t he reserve( ) m em ber
funct ion:
int m ain( )
{
vect or < Message > m sgs;
m sgs.reserve( 1000) ; / * m ake room for 1000 Message elem ent s* /
/ / ...insert elem ent s
}
reserve( n) allocat es st orage for at least n elem ent s ( not byt es) , t hereby ensuring
t hat t he cont ainer doesn’t reallocat e m em ory as long as t he num ber of elem ent s
doesn’t exceed n.
I n h e r it in g Fr om A Cla ss Th a t H a s N o Vir t u a l D e st r u ct or
Classes having a nonvirt ual dest ruct or aren’t m eant t o serve as base classes ( such
classes are usually known as "concret e classes") . st d: : st ring, st d: : com plex, and
st d: : vect or are concret e classes. Why is inherit ing from such classes not
recom m ended? When you use public inherit ance, you creat e an is- a relat ionship
bet ween t he base class and t he derived class. Consequent ly, point ers and references
t o base can point t o a derived obj ect . Because t he dest ruct or isn’t virt ual, C+ + will
not call t he ent ire dest ruct or chain when you delet e such an obj ect . For exam ple:
class A
{
public:
~ A( ) / / non virt ual
{
/ / ...
}
};
int m ain( )
{
A * p = new B; / * seem ingly OK* /
delet e p; / * t rouble, B’s dt or not called* /
}
The result of failing t o invoke an obj ect ’s dest ruct or is undefined. Therefore, you
shouldn’t use publicly inherit from such classes.
Th e Bin a r y_ Se a r ch Algor it h m
STL’s binary_search( ) algorit hm t raverses a sequence and ret urns a bool value
indicat ing whet her t he sought - aft er elem ent exist s in t hat sequence. binary_search( )
is declared in < algorit hm > as follows:
binary_search( ) t akes t wo forward it erat ors t hat m ark t he sequence’s bounds and
t he sought - aft er value as t he t hird argum ent . I t ret urns t rue if t he sought - aft er value
exist s in t he sequence, or false ot herwise. I n t his exam ple, binary_search( ) checks
whet her t he int egers 5 and 0 exist in a vect or of int egers:
The st andard header < iosfwd > cont ains forward declarat ions of t he st andard I / O
classes and t em plat es. This header is sufficient t o refer t o any of t he I / O classes and
t em plat es, but not t o apply operat ion t o t hem . For exam ple:
I n t he exam ple, t he declarat ion of t he friend funct ion does not need a com plet e
definit ion of t he ost ream class; a forward declarat ion is sufficient in t his case.
Therefore, < iosfwd > is # included inst ead of t he full- blown < iost ream > . The result
is a significant ly reduced com pilat ion t im e.
I t is possible t o override t he operat ors new and delet e and define a specialized
version of t hem for a given class. Thus, for a class C t hat defines t hese operat ors,
t he st at em ent s
C* p = new C;
delet e p;
invoke t he class’s versions of new and delet e, respect ively. Defining class- specific
versions of new and delet e is useful when t he default m em ory m anagem ent schem e
is unsuit able, or for debugging purposes.
Not e t hat overloaded new and delet e are im plicit ly declared st at ic. Rem em ber also
t hat a user- defined new im plicit ly invokes t he obj ect ’s const ruct or; likewise, a user-
defined delet e im plicit ly invokes t he obj ect ’s dest ruct or.
There are a few sem ant ic differences bet ween C and C+ + in t he int erpret at ion of
cert ain language const ruct s. These differences m ay not result in a com piler
diagnost ic, and t herefore, it is im port ant t o pay at t ent ion t o t hem when port ing code
from a C com piler t o a C+ + com piler, and vice versa.
A t em plat e can t ake t he address of an obj ect wit h ext ernal linkage as an argum ent .
Consequent ly, you cannot use a st ring lit eral as a t em plat e argum ent since st ring
lit erals have int ernal linkage. For t he sam e reason, you cannot use local point ers for
t hat purpose, eit her. For exam ple:
An obj ect is a cont iguous region of m em ory st orage. An lvalue ( pronounced L value)
is an expression t hat refers t o such an obj ect ( t he original definit ion of lvalue
referred t o "an obj ect t hat can appear on t he left - hand side of an assignm ent ") . An
expression t hat can appear on t he right - hand side of an expression ( but not on it s
left - hand side) is an rvalue. For exam ple:
An lvalue can appear in a cont ext t hat requires an rvalue; in t his case, t he lvalue is
im plicit ly convert ed t o an rvalue. However, an rvalue cannot be convert ed t o an
lvalue. Therefore, it is possible t o use every lvalue expression in t he exam ple as an
rvalue, but not vice versa.
The fam ous "Big Three Rule" says t hat if a class needs any of t he Big Three m em ber
funct ions ( copy const ruct or, assignm ent operat or, and dest ruct or) , it needs all of
t hem . I n general, t his rule refers t o classes t hat allocat e m em ory from t he free st ore.
However, m any ot her classes require only t hat t he Big Two ( copy const ruct or and
assignm ent operat or) be defined by t he user; t he dest ruct or, nonet heless, is not
always required. Exam ine t he following exam ple:
class Year
{
privat e:
int y;
bool cached; / * has t his inst ance been cached? * /
public:
Year( int y) ;
Year( const Year & ot her) / * m ake sure ’cached’ isn’t copied * /
{
y = ot her.get Year( ) ;
}
Year & operat or = ( const Year & ot her) / * m ake sure ’cached’ isn’t copied * /
{
y = ot her.get Year( ) ;
ret urn * t his;
}
int get Year( ) const { ret urn y; }
} ; / * no dest ruct or is required for class Year * /
Class Year does not allocat e m em ory from t he free st ore, nor does it acquire any
ot her resources during it s const ruct ion. A dest ruct or is t herefore unnecessary.
However, t he class needs a user- defined copy const ruct or and assignm ent operat or
t o ensure t hat value of t he m em ber ’cached’ is not copied, because it is calculat ed
for every individual obj ect separat ely.
Writ ing code from scrat ch, wit hout any prior design or plan, is bad program m ing
pract ice. However, t he opposit e- - over- engineering- - can be j ust as harm ful. Over-
engineering is t he use of cost ly, redundant , or "cut e" feat ures t hat aren’t t ruly
necessary or t hat have sim pler and efficient alt ernat ives. A good exam ple of t his is
using except ion handling as an alt ernat ive t o while and for st at em ent s. Sim ilarly,
t em plat izing a class or funct ions t hat are never used for m ore t han a single t ype is
an expensive and redundant t ask. "Cut e" feat ures and puns such as m acro t rickery
can also result in indecipherable code. However, t he worst of all is probably a wheel’s
reinvent ion. Writ ing cust om cont ainer classes and algorit hm s inst ead of using t he
ones t hat are readily available in C+ + ( in t he form of STL) is expensive, bug prone,
and t ot ally uncalled for. One of t he phases of design and code reviews should consist
of cat ching and sift ing such inst ances of over- engineering, wheel reinvent ion, and
"poet ry."
D ECLARI N G A TYPED EF
As you m ay know, t ypedef nam es can hide int ricat e synt act ic const ruct s such as
point ers t o funct ions or com plex t em plat e declarat ions. However, m any novices
sim ply don’t know how t o declare or int erpret a t ypedef declarat ion.
To writ e a t ypedef declarat ion, sim ply define a variable of t he desired t ype. Suppose
you want t o creat e a t ypedef nam e t hat represent s "point er t o int ". First , define a
point er t o int :
int * pi;
Now t he nam e pi serves as a synonym for "point er t o int ". You can use pi in any
cont ext t hat requires a point er t o int :
pi pt r = new int ;
Sim ilarly, t o creat e a t ypedef nam e t hat is synonym ous wit h "point er t o funct ion t hat
ret urns int and t akes int ", you first declare such a point er:
I n t he definit ion above, pfi is a point er t o a funct ion t hat ret urns int and t akes int .
Now, add t he keyword "t ypedef" before t he definit ion:
And pfi becom es a t ypedef nam e for "point er t o funct ion t hat ret urns int and t akes
int ". For exam ple:
/ * File a.cpp * /
const int x= 0;
/ * File b.cpp * /
const int x = 2; / * a different x * /
/ * File m ain.cpp * /
int m ain( )
{
}
Bot h a.cpp and b.cpp define a const variable called x. However, t he t wo definit ions
don’t clash because t hey refer t o dist inct variables, each of which has a different
value and is visible only from t he scope of it s source file. I f you rem ove t he const
qualifier from t he definit ion of bot h x’s, recom pile all t he source files, and relink
t hem , you will receive a linker error:
This is because x has ext ernal linkage when it ’s not declared const . As a result , t he
t wo definit ions of x clash.
There are t wo lessons from t his exam ple. First , if you wish t o m ake a const obj ect
declared in t he global scope globally accessible, you m ust declare it ext ern. Second,
avoid declaring nonlocal const obj ect s st at ic, as in
st at ic const int x = 0;
There’s a com m on m yt h am ong program m ers t hat it ’s okay t o use delet e inst ead of
delet e[ ] t o release arrays of built - in t ypes. For exam ple,
This is t ot ally wrong. The C+ + st andard specifically says t hat using delet e t o release
dynam ically allocat ed arrays of any t ype yields undefined behavior. The fact t hat , on
som e plat form s, applicat ions t hat use delet e inst ead of delet e[ ] don’t crash can be
at t ribut ed t o sheer luck: Visual C+ + , for exam ple, im plem ent s bot h delet e[ ] and
delet e for built - in t ypes by calling free( ) . However, t here is no guarant ee t hat fut ure
releases of Visual C+ + will adhere t o t his convent ion. Furt herm ore, t here’s no
guarant ee t hat t his code will work on ot her com pilers. So, using delet e inst ead of
delet e[ ] , and vice versa, is precarious and should be avoided.
C+ + dist inguishes bet ween t wo init ializat ion t ypes for obj ect s wit h st at ic st orage
durat ion ( global obj ect s, local st at ic obj ect s, and obj ect s declared in nam espace
scope have st at ic st orage) . St at ic init ializat ion consist s of eit her zero- init ializat ion or
init ializat ion wit h a const ant expression; any ot her init ializat ion is considered
dynam ic init ializat ion. These t wo t ypes roughly correspond t o com pile- t im e
init ializat ion and runt im e init ializat ion. For exam ple:
int x = func( ) ;
int m ain( )
{
}
I n ot her words, obj ect s wit h st at ic st orage m ay be init ialized t wice: once by st at ic
init ializat ion, during which t heir m em ory st orage is init ialized t o binary zeroes, and
aft erwards, when t heir const ruct ors perform addit ional dynam ic init ializat ion.
Alt hough t he use of global variables is not recom m ended in general, som et im es it ’s
unavoidable. When using a global variable or obj ect , never inst ant iat e it in a header
file because t he header is usually # included in several separat e source files.
Consequent ly, t he linker will com plain on m ult iple definit ions of t he sam e obj ect .
I nst ead, inst ant iat e a global in a single .cpp file. This way, you ensure t hat it ’s
defined only once, regardless of t he num ber of source files used in t he proj ect . All
ot her source and header files in t he proj ect t hat refer t o t hat global obj ect need t o
declare it ext ern. Here is an exam ple:
/ / File a.h
/* * * * * * * * * /
st ruct Count er
{
Count er( ) { + + x; }
~ Count er( ) { - - x; }
};
/ / File b.cpp
/* * * * * * * * * /
/ / File m ain.cpp
/* * * * * * * * * /
# include "a.h"
int m ain( )
{
Count er count ;
int n = x;
}
The t wo source files, b.cpp and m ain.cpp, are com piled separat ely. At
link t im e,
t he linker resolves all references t o x t o t he variable defined in
b.cpp.
Many program m ers st ill use hom em ade ( or worse yet - - handm ade) cont ainer classes
such as list and vect or inst ead of using t he St andard Tem plat e Library ( STL) . There
are significant advant ages in preferring STL cont ainers t o any ot her cont ainer
fram ework: STL cont ainers are port able, t heir perform ance is usually superior, and
t hey have already been debugged and t est ed for you.
I oft en receive readers’ queries regarding nonst andard header files t hey don’t have
and would like t o inst all, such as < conio.h ,, et c. This header chase is fut ile in m ost
cases. I f your developm ent environm ent doesn’t provide t hese header files, chances
are good t hat t he funct ions t hey declare aren’t support ed on your plat form anyway.
Consequent ly, you won’t be able t o link a program t hat uses any of t hese funct ions.
I N LI N E AN D COD E BLOAT
I received an int erest ing quest ion from a reader. He used STL’s vect or in a class t hat
was heavily used in his proj ect . The t wo com pilers he used produced an ext rem ely
bloat ed execut able file in debug m ode. Alt hough t he release m ode was m uch
slim m er, he wondered what was causing t his code bloat . I t appears t hat t he use of
"inline" in vect or’s operat or [ ] increased t he execut able’s size dram at ically. When he
rem oved t he inline specifier from vect or’s operat or [ ] , his applicat ion shrank
significant ly.
There are t wo lessons from t his st ory. First , if you discover t hat your applicat ion’s
size is bloat ed, you should review all t he occurrences of inline funct ions, am ong
ot her t hings. Second, you should avoid t he use of "inline" unless you’re absolut ely
sure t hat it im proves perform ance rat her t han degrades it .
W H AT’S I N A BYTE
Many believe t hat a byt e, by definit ion, is an 8- bit dat a unit . Technically, t his
definit ion isn’t necessarily so. A byt e is a dat a unit wit h an unspecified num ber of
bit s. I ndeed, m ost hardware archit ect ures nowadays use 8- bit byt es. However, 20
and 30 years ago, m achines t hat had 6- bit byt es, 9- bit byt es, and ot her weird
num bers weren’t except ional. For t his reason, com m unicat ion prot ocols and ot her
st andards ( such as CORBA) use t he t erm oct et t o refer t o a dat a unit t hat occupies
exact ly 8 bit s. For exam ple, an I P address consist s of 4 oct et s.
The newly approved C99 st andard defines a new header file called < int t ypes.h > ,
which defines set s of t ypedefs of int eger t ypes. One of t hese set s defines int eger
t ypes wit h cert ain exact widt hs:
The nam es are rat her int uit ive. For exam ple, int 8_t is a signed int egral t ype t hat
occupies exact ly 8 bit s. Likewise, uint 8_t is an unsigned int egral t ype t hat occupies
exact ly 8 bit s. Use t hese t ypedef nam es when you need int egers whose widt hs are
ident ical on every plat form .
Many program m ers st ill use t he nonst andard, plat form - dependent BOOL t ypedef
inst ead of using bool. There are m any good reasons why you shouldn’t use BOOL;
one of t hem has t o do wit h t he size of t his t ype. Unlike bool, which occupies one byt e
on m ost plat form s, BOOL usually occupies four byt es. Because of t his, BOOL causes
an unnecessary increase in t he size of your classes. Consider:
class Bloat ed
{
BOOL a;
BOOL b;
BOOL c;
BOOL d;
};
class Slim
{
bool a;
bool b;
bool c;
bool d;
};
D ELETI N G A FI LE
The st andard funct ion rem ove( ) delet es a file. I t t akes one argum ent of t ype const
char* t hat cont ains a filenam e. You can provide a full pat h as a filenam e. On
success, rem ove( ) ret urns 0. A non- zero ret urn code indicat es an error. For exam ple:
I n low- level program m ing and hardware int erfaces, you oft en need t o assign a
point er t o a specific physical address. To do t hat , cast t he address value using t he
reint erpret _cast operat or. Here’s an exam ple:
void * p;
/ * assign address 0x5800FF t o p* /
To block copying and assignm ent of a class obj ect , explicit ly declare it s assignm ent
operat or and copy const ruct or privat e. Don’t define t hem ; only declare t hem . I n t his
exam ple, class A has a public default const ruct or. I n addit ion, it declares a privat e
copy const ruct or and assignm ent operat or t o ensure t hat obj ect s of it s class can’t be
copied or assigned t o:
class a
{
public:
A( ) { }
privat e:
A( const A& ) ; / * declared; not im plem ent ed* /
A& operat or= ( const A& ) ; / * dit t o* /
};
int m ain( )
{
A a; / * fine, default ct or is public* /
A b ( a) ; / * error, copy ct or is inaccessible* /
A c; / * fine* /
c = a; / * error, assignm ent operat or is inaccessible* /
}
I M PLI CI T I N T I SN ’T ALLOW ED
volat ile x;
const y = 0;
I n prest andard C+ + , t he default t ype in such incom plet e declarat ions was int . Thus,
t hese declarat ions would declare x as volat ile int and y as const int . However, t he
C+ + st andard was changed several years ago. Declarat ions wit h im plicit int aren’t
allowed anym ore. You have t o specify t he variable’s t ype explicit ly:
Many com pilers aren’t yet com pliant in t his respect and accept t he incom plet e
declarat ions given above. You shouldn’t count on t his, because fut ure versions of
your com piler will flag such declarat ions as errors.
This isn’t t he best way t o declare t em plat e param et ers, because it m eans t hat T will
be passed by value. To avoid t his, pass t em plat e param et ers by reference:
t em plat e < class T > bool equal ( T& first , T& sec) ;
Linkage bet ween C+ + and non- C+ + code can be achieved using a linkage
specificat ion. For exam ple:
ext ern "C" int func( int arg1) ; / * func has C linkage* /
The quot ed st ring in t he linkage specificat ion indicat es t he required language linkage.
The linkage rules of a given language affect t he way funct ion nam es are handled- - for
exam ple, case, nam e m angling, and argum ent - passing m echanism s. Using a linkage
specificat ion wit h a nam e t hat is unknown t o t he im plem ent at ion is an error. A C+ +
com piler m ust support t wo linkage t ypes: ext ern "C" and ext ern "C+ + ". The lat t er is
t he default linkage t ype and is t herefore redundant . Many im plem ent at ions support
addit ional languages- - for inst ance:
To com put e t he t im e t hat elapsed bet ween t wo dat es, use t he st andard funct ion
difft im e( ) . This way, you avoid pot ent ial bugs such as leap years or Y2K issues.
difft im e( ) t akes t wo variables of t ype t im e_t , each represent ing a dat e, and ret urns
t he num ber of seconds t hat elapsed bet ween t hem . For exam ple:
I n pre- st andard C+ + , t he st rst ream fam ily of classes was used as buffered st ream
classes. These classes are now considered deprecat ed; you should use t he
st ringst ream fam ily of classes inst ead. For exam ple, t he following code ( which uses
t he deprecat ed ost rst ream class) :
The ost ringst ream class ret urns a st ring obj ect rat her t han char * . I n addit ion, it ’s
declared in nam espace st d. As a rule, use st ringst ream , ist ringst ream , and
ost ringst ream inst ead of t he deprecat ed st rst ream , ist rst ream , and ost rst ream
classes, respect ively.
A funct ion t hat can be safely called while it ’s already execut ing is said t o be re-
ent rant . C+ + doesn’t st at e whet her t he St andard Library’s funct ions are re- ent rant ;
t his is an im plem ent at ion- dependent feat ure. What ’s t he use of calling a funct ion
while it ’s already execut ing? There are t wo occasions in which t his scenario can
happen:
- When t he funct ion is invoked by t wo or m ore dist inct t hreads of t he sam e process
- When a program execut es a signal handler t hat raises t he sam e signal once again
I n eit her case, rem em ber t hat calling a non- re- ent rant funct ion while it ’s already
execut ing is undefined.
Cert ain applicat ions need t o invoke st art up funct ions t hat run before t he m ain
program st art s. For exam ple, polling, billing, and logger funct ions m ust be invoked
before t he act ual program begins. The easiest way t o achieve t his is by calling t hese
funct ions from a const ruct or of a global obj ect . Because global obj ect s are
concept ually const ruct ed before t he program ’s out set , t hese funct ions will run before
m ain( ) st art s. For exam ple:
class Logger
{
public:
Logger( )
{
log_user_act ivit y( ) ;
}
};
Logger log; / * global inst ance* /
int m ain( )
{
record * prec= read_log( ) ;
/ / .. applicat ion code
}
The global obj ect log is const ruct ed before m ain st art s. During it s const ruct ion, log
invokes t he funct ion log_user_act ivit y( ) . When m ain( ) st art s, it can read dat a from
t he log file.
M I N I M I ZE TH E USE OF TH E EN D L M AN I PULATOR
The bot t om line: Avoid using t he endl m anipulat or if you can, because it m ight
degrade perform ance unnecessarily.
TI ED I OSTREAM OBJECTS
The st andard st ream s cin and cout are aut om at ically t ied t o one anot her. This m eans
t hat whenever you use t hem , C+ + ensures t hat t heir operat ion is synchronized. I n
ot her words, if you have
int m ain( )
{
st d: : st ring s( "hello") ; / / lowercase
/ * t ransform st ring t o uppercase * /
st d: : t ransform ( s.begin( ) , / * original st ring’s beginning* /
s.end( ) , / * original st ring’s end* /
s.begin( ) , / * where t o writ e new st ring?* /
t oupper) ; / * unary operat or * /
Alas, t his program will not com pile because t he nam e t oupper is am biguous. To
resolve t he am biguit y, add an explicit cast :
This t ells t he com piler t o choose t he t oupper( ) version declared in < cct ype > . I n a
sim ilar vein, you can t ransform a st ring t o lowercase let t ers by using t he t olower( )
funct ion.
I TERATOR CATEGORI ES
The St andard Tem plat e Library defines five m aj or cat egories of it erat ors. These
cat egories are
- I nput it erat ors + out put it erat ors
- Forward it erat ors
- Bidirect ional it erat ors
- Random access it erat ors
Not e t hat t his list doesn’t represent inherit ance relat ionships; it m erely describes t he
it erat or cat egories and t heir int erfaces. Each lower cat egory is a superset of t he
cat egory above it . For inst ance, a bidirect ional it erat or provides all t he funct ionalit y
of a forward it erat or plus addit ional funct ionalit y. Here is a brief sum m ary of t he
funct ionalit y and int erfaces of t hese cat egories:
- I nput it erat ors allow an algorit hm t o advance t he it erat or and offer read- only
access t o an elem ent .
- Out put it erat ors allow an algorit hm t o advance t he it erat or and offer writ e- only
access t o an elem ent .
- Forward it erat ors support bot h read and writ e access, but t raversal is perm it t ed
only in one direct ion.
- Bidirect ional it erat ors allow t he user t o t raverse t he sequence in bot h direct ions.
- Random access it erat ors support random j um ps and "point er arit hm et ic"
operat ions, for exam ple:
Oft en, applicat ions t hat are free from m em ory leaks but frequent ly allocat e and
deallocat e dynam ic m em ory show gradual perform ance degradat ion if t hey are kept
running for long periods. Finally, t hey crash. Why is t his?
Recurrent allocat ion and deallocat ion of dynam ic m em ory causes t he heap t o becom e
fragm ent ed, especially if t he applicat ion allocat es sm all m em ory chunks. A
fragm ent ed heap m ight have m any free blocks, but t hese blocks are sm all and
noncont iguous. To dem onst rat e t his, look at t he following schem e t hat represent s
t he syst em ’s heap. Zeros indicat e free m em ory blocks, and ones indicat e m em ory
blocks t hat are
in use:
100101010000101010110
The above heap is highly fragm ent ed. Allocat ing a m em ory block t hat cont ains five
unit s ( t hat is, five zeros) will fail, alt hough t he syst em has 12 free unit s in t ot al. This
is because t he free m em ory isn’t cont iguous. On t he ot her hand, t he following heap
has less free m em ory, but it ’s not fragm ent ed:
1111111111000000
What can you do t o avoid heap fragm ent at ion? First , use dynam ic m em ory as lit t le
as possible. I n m ost cases, you can use st at ic or aut om at ic st orage or use STL
cont ainers. Second, t ry t o allocat e and deallocat e large chunks rat her t han sm all
ones. For exam ple, inst ead of allocat ing a single obj ect , allocat e an array of obj ect s
at once. As a last resort , use a cust om m em ory pool.
Tem plat es can have default t ype param et ers. The com piler uses t hese default t ypes
when you don’t provide t hem explicit ly in a t em plat e inst ant iat ion. For exam ple:
You inst ant iat e a t em plat e wit h default t ype param et ers like t his:
int m ain( )
{
E < unsigned,int > e1( 0,0) ; / * OK, explicit t ypes* /
E < > e2( ’a’,’b’) ; / * OK, using default * /
}
Alt hough usually I don’t recom m end using m acros in C+ + code, t here are a few
except ions. One such except ion is when you want t o creat e a t ruly im m ut able
const ant . Consider t his const ant :
Seem ingly, MAX’s value can’t be changed because it ’s const . However, on som e
plat form s, a brut e- force cast can change it s value. For exam ple:
Any at t em pt t o change a const obj ect causes undefined behavior. However, som e
im plem ent at ions let t his hack pass unnot iced. To disable it alt oget her, you can use a
m acro inst ead of a const obj ect :
SI GN ED BI T FI ELD S
A bit field can be signed or unsigned. When you declare a signed bit field, rem em ber
t hat it m ust occupy at least t wo bit s, because one bit is always reserved for t he sign.
An unsigned bit field can occupy a single bit . Such a field can only have t he values 1
or 0:
st ruct BI TS
{
I t ’s cust om ary t o use out put st at em ent s as a debugging aid t o display t he nam e of a
funct ion t hat is current ly in scope or t o print a variable’s value on t he screen. These
st at em ent s are aut om at ically rem oved from t he release version of t he applicat ion by
m acro m agic. For exam ple:
void func( )
{
int n;
n = sqrt ( n) ;
# ifdef DEBUG / * code below exist s only in debug version * /
cout < < "value of n: " < < n < < endl;
# endif
}
Seem ingly, t he st at em ent s enclosed in # ifdef m acros don’t incur any overhead in t he
release version because t he preprocessor rem oves t hem when t he sym bol DEBUG
isn’t defined. However, program m ers oft en forget t o enclose t he # include < iost ream
> direct ive wit hin an # ifdef clause. The < iost ream > obj ect s add a subst ant ial
am ount of code t o t he program , increasing t he execut able’s size and m em ory
foot print . Therefore, rem em ber t o rem ove t he # include direct ive if your app doesn’t
use any of t he iost ream obj ect s. Alt ernat ively, you can wrap t he # include direct ive in
an # ifdef clause:
# ifdef DEBUG
# include < iost ream > / * not included in release version * /
# endif
An incom plet e array declarat ion can appear in a funct ion’s param et er list . For
exam ple:
The declarat ion of s doesn’t include t he array’s size. Can count ( ) use t he operat or
sizeof t o calculat e s’s size? No, it can’t . The com piler im plicit ly t ransform s an array
int o a point er. Therefore, sizeof ret urns a point er’s size, not an array’s size. One way
t o obt ain t he array’s size is t o pass an addit ional argum ent t hat holds t he num ber of
elem ent s in t he array:
However, a bet t er solut ion is t o pass a vect or and call it s size( ) m em ber funct ion:
{
ret urn s.size( ) ;
}
C+ + allows you t o declare variables j ust before t heir use rat her t han at t he t op of
t he enclosing block. For exam ple, you m ay declare a variable inside t he condit ion of
an if- st at em ent :
The advant age of declaring t he point er pd locally is obvious: I t ’s always init ialized
properly, and it isn’t visible t o ot her part s of t he program t hat shouldn’t use it .
if ( x = get val( ) )
{
/ * do som et hing * /
}
The if condit ion is evaluat ed in t wo st eps: First , t he uncondit ional assignm ent t o x
t akes place. Then, x is checked. The if- block is execut ed only if x’s value ( aft er t he
assignm ent ) isn’t 0. Alt hough t his t echnique can save you a few keyst rokes, it ’s
highly dangerous and should be avoided. The problem is t hat one can easily m ist ake
= = for = or vice versa. For t his reason, several com pilers issue a warning m essage
if you place an assignm ent expression inside an if condit ion, t o draw your at t ent ion
t o a pot ent ial bug. I f you need t o assign a value and t est t he result , separat e t hese
st eps int o t wo dist inct st at em ent s:
x = get val( ) ;
if ( x)
{
/ * do som et hing * /
}
This way, you docum ent your int ent ion m ore clearly and avoid t his pot ent ial bug.
if ( x= = 4) / * 4 is an rvalue* /
...
if ( y! = MAX_COUNT) / * MAX_COUNT is a const ant * /
...
if ( 4= = X)
...
if ( MAX_COUNT! = y)
...
Because t he equalit y and inequalit y operat ors are com m ut at ive, reversing t he order
of t heir operands doesn’t change t he result . However, t he benefit is t hat a reversed
order saves you from using = inst ead of = = by m ist ake. I f you put = inst ead of = =
in a reversed order expression, for exam ple:
your com piler will cat ch t he error and com plain about an at t em pt t o assign t o an
rvalue.
Personally, I don’t like t he reverse order t rick because it m akes t he code som ewhat
dist ort ed: The program m er’s int ent ion is t o check t he value of x, not t he value of t he
const ant 4. St ill, if you find yourself m ist aking = for = = , you m ay adopt t his coding
st yle. Not e t hat a good com piler should warn about assignm ent s inside condit ions,
which m akes t his t echniques less needed t han it m ight seem at first .
By default , a t ypedef nam e declared in t he global scope has int ernal linkage. This
m eans t hat a separat ely com piled source file can’t refer t o a t ypedef declared in
anot her source file, unless t hat t ypedef is explicit ly declared "ext ern". I n t his respect ,
C+ + is different from C, which m akes t ypedef nam es global by default . For t his
reason, in C+ + you are allowed t o define t he sam e t ypedef nam e in every separat ely
com piled source file as long as t he definit ions are ident ical:
/ * file second.cpp * /
t ypedef int I ; / * visible only in t he scope of t his file * /
float func2( I ) ;
int m ain( )
{
list < node & > ln; / * error * /
}
I f you t ry t o com pile t his exam ple, your com piler will issue num erous com pilat ion
errors. The problem is t hat list < T > has m em ber funct ions t hat t ake or ret urn T&.
I n ot her words, t he com piler t ransform s < node & > t o < node && > . Since a
reference t o a reference is illegal in C+ + , t he program is ill form ed. As a rule, you
should inst ant iat e t em plat es in t he form of list < node > and never as list < node &
>.
The t erm s "argum ent " and "param et er" are oft en used int erchangeably in t he
lit erat ure, alt hough t he C+ + St andard m akes a clear dist inct ion bet ween t he t wo.
The following exam ple dem onst rat es t he difference bet ween a param et er and an
argum ent :
int m ain( )
{
char c;
char * p = & c;
func( 5, p) ; / * 5 and p are argum ent s * /
A &< long &> a; / * ’long’ is an argum ent * /
A &< char &> anot her_a; / * ’char’ is an argum ent * /
ret urn 0;
}
Part of t he code for yest erday’s t ip cam e out incorrect ly. Here is t he
t ip as it should have appeared yest erday. We apologize for any
incovenience.
int m ain( )
{
list &< node &&> ln; / * error * /
}
I f you t ry t o com pile t his exam ple, your com piler will issue num erous com pilat ion
errors. The problem is t hat list &< T &> has m em ber funct ions t hat t ake or ret urn
T&. I n ot her words, t he com piler t ransform s &< node & &> t o &< node && &> . Since
a reference t o a reference is illegal in C+ + , t he program is ill form ed. As a rule, you
should inst ant iat e t em plat es in t he form of list &< node &> and never as list &<
node &&> .
On e Sm a r t Click .Com