Sie sind auf Seite 1von 64

D ow nloa de d fr om One Sm a r t Click .

Com

C+ + : Tips, Tr ick s a nd H int s


PART I I

Sou r ce : TipWorld Newslet t er By D a nny Ka le v


Com piled by Pr a sh a n t N . M h a t r e

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.

Use at your own risk. I assum e no responsibilit y.

More docum ent s like t his:

On e Sm a r t Click .Com

C+ + Tips and Trick s – Part 2 1


D ow nloa de d fr om One Sm a r t Click .Com

D e t e ct in g H ow M a n y File s a Pr oce ss Ca n Ope n Sim u lt a n e ou sly

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

Several special charact ers are represent ed as escape sequences. An escape


sequence begins wit h a \ ( backslash) followed by an alphanum eric charact er. For
exam ple, t he \ n escape sequence represent s t he new line charact er. Not e t hat t he
t wo charact ers of an escape sequence are const rued as a single charact er. Here’s a
list of C+ + escape sequences:

\ 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* /

CALLI N G A FUN CTI ON TH ROUGH A POI N TER

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* /

Un de r st a n din g CON ST_ I TERATORS

A recent subscriber of one of t he C+ + newsgroups post ed t he following quest ion:


"Why does C+ + have a const _it erat or inst ead of a const it erat or? And why not
require const _it erat or act ually t o be of t ype ’const it erat or’?"

C+ + Tips and Trick s – Part 2 2


D ow nloa de d fr om One Sm a r t Click .Com

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:

t ypedef st d: : vect or < int > VI ;


VI vi;
vi.push_back( 1) ;
vi.push_back( 2) ;
VI : : const _it erat or it = vi.begin( ) ;
+ + it ; / * fine, not changing t he elem ent ’s value* /
* it = 5; / * error, can’t change an elem ent via const _it erat or* /

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:

void func( const int arr[ ] , size_t lengt h ) ;


int m ain( )
{
vect or < int > vi;
/ / .. fill vi
func( &vi[ 0] , vi.size( ) ) ;
}

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.

Th e VECTOR::D ATA( ) M e m be r Fu n ct ion

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.

C+ + Tips and Trick s – Part 2 3


D ow nloa de d fr om One Sm a r t Click .Com

Com m a - Se pa r a t e d Ex pr e ssion s

An expression m ay consist of one or m ore subexpressions separat ed by com m as. For


exam ple:

if( + + x, - - y, cin.good( ) ) / * t hree expressions* / /

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.

ERASI N G ELEM EN TS OF ASSOCI ATI VE CON TAI N ERS

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( ) :

class m ap / * sim plified for brevit y* /


{
public:
void erase( it erat or posit ion) ; / / 1
size_t ype erase( const key_t ype& x) ; / / 2
void erase( it erat or first , it erat or last ) ; / / 3
};

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:

C+ + Tips and Trick s – Part 2 4


D ow nloa de d fr om One Sm a r t Click .Com

st d: : m ap< int , st d: : st ring > em ployees;


/ / .. fill m ap
/ / erase t he elem ent whose first m em ber equals 2 em ployees.erase( 2) ;

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:

em ployees.erase( em ployees.begin( ) , em ployees.end( ) ) ;

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

The st andard funct ion t m pfile( ) is declared in ( form erly ) as follows:

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:

enum St at { good= 1, bad= 2} ; / * no enum erat or equals 0* /


St at st ; / * bad, init ialized t o 0 by default * /
int m ain( )
{
if( st = = good) / / always false
/ / ...
}

I t ’s best always t o init ialize enum variables explicit ly, t hereby avoiding such bugs:

St at st = good;

C+ + Tips and Trick s – Part 2 5


D ow nloa de d fr om One Sm a r t Click .Com

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.

CH ECKI N G A STREAM ’S STATE

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:

bool good( ) / * t rue if no error flag is set * /


bool eof( ) / * t rue if eofbit is set * /
bool fail( ) / * t rue if failbit or badbit is set * /
bool bad( ) / * t rue if badbit is set * /
bool operat or! ( ) / * as fail( ) * /
operat or void* ( ) / * ret urns null if fail( ) is t rue* /

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) ;

H I D I N G CUM BERSOM E FUN CTI ON POI N TER SYN TAX

Can you t ell what t he following declarat ion m eans?

void ( * p[ 10] ) ( void ( * ) ( ) ) ;

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

C+ + Tips and Trick s – Part 2 6


D ow nloa de d fr om One Sm a r t Click .Com

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:

t ypedef void ( * pfv) ( ) ;

Next , declare anot her t ypedef for "point er t o a funct ion ret urning void and t aking a
pfv":

t ypedef void ( * pf_t aking_pfv) ( pfv) ;

Now declaring an array of 10 such point ers is a breeze:

pf_t aking_pfv p[ 10] ; / * equivalent t o


void ( * p[ 10] ) ( void ( * ) ( ) ) ; but m uch m ore readable* /

STATI C_ CAST ve r su s REI N TERPRET_ CAST

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.

Block s An d Com pou n d St a t e m e n t s

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:

for ( int n= 0; n< 100; + + n)


{
/ / .. a com pound st at em ent
}

C+ + Tips and Trick s – Part 2 7


D ow nloa de d fr om One Sm a r t Click .Com

void func( )
{
/ / .. a com pound st at em ent
}

St or in g D yn a m ica lly Alloca t e d Obj e ct s I n STL Con t a in e r s

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{ } ;

vect or < Base * > v;


v.push_back( new Derived) ;
v.push_back( new 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] ;

D e bu g I n for m a t ion I n A Re le a se Ve r sion

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:

enum Direct ion ( Up, Down} ;


Direct ion dir;
dir= 0; / * error, can’t assign int t o enum t ype* /

You need t o use st at ic_cast t o explicit ly cast an int eger t o an enum erat ion:

dir= st at ic_cast < Direct ion > ( 0) ; / * dir equals ’Up’* /

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:

C+ + Tips and Trick s – Part 2 8


D ow nloa de d fr om One Sm a r t Click .Com

dir= st at ic_cast < Direct ion > ( 5) ; / * undefined behavior* /

Therefore, use t his t echnique wit h caut ion.

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:

int fact orial ( int num )


{
if ( num = = 1)
ret urn 1;
ret urn fact orial( num - 1) * num ; / * recursive call* /
}

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:

int fact orial ( int num )


{
int result = 1;
for ( int i= 1; i< = num ; + + i) result * = i;
ret urn result ;
}

The nonrecursive version is slight ly fast er because it avoids t he overhead of


recurrent funct ion calls.

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:

int func( int dim )


{
int arr[ dim ] ; / * possible only in C99* /
}

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 ) ;

C+ + Tips and Trick s – Part 2 9


D ow nloa de d fr om One Sm a r t Click .Com

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:

char * t m pnam ( char * nam e) ;

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:

# include < cst dio >


# include < iost ream >
using nam espace st d;
int m ain( )
{
char nam e[ L_t m pnam ] = { 0} ;
for ( int n= 0; n
{
t m pnam ( nam e) ;
cout < < nam e < < endl;
}
}

Elim in a t in g Bu ffe r Ove r flow s

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:

# include < cst dio >


int m ain( )
{
char buff[ 15] = { 0} ;
print f( "ent er your nam e: ") ;
scanf( buff, "% s") ; / * dangerous, lengt h unchecked* /
}

C+ + Tips and Trick s – Part 2 10


D ow nloa de d fr om One Sm a r t Click .Com

The program reads a st ring from t he st andard input ( t he keyboard) . However, it


doesn’t check t he st ring’s lengt h. I f t he st ring has m ore t han 14 charact ers, it causes
a buffer overflow as scanf( ) t ries t o writ e t he rem aining charact ers past buff’s end
( rem em ber t hat one charact er is always reserved for a null t erm inat or) . The result is
m ost likely a runt im e crash. On som e syst em s, t he users will receive a shell’s prom pt
aft er t he crash. Even if t he shell has rest rict ed privileges, end users can st ill exam ine
environm ent variables and list t he current direct ory files. Alt hough t he program uses
C- st yle I / O operat ions, such code is st ill widely used t oday.

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 :

char buff[ 15] = { 0} ;


fget s( buff, sizeof( buff) , st din) ; / * read at m ost 14 chars* /

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;

st d: : st ring aut om at ically allocat es m em ory as necessary. Therefore, a buffer


overflow can’t happen in t his case unless t he syst em is in a pat hological st at e.

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 powl( double x, double y) ;

pow( ) ret urns t he value calculat ed of x t o t he power of y. For exam ple:

double x= 10, y= 4;
double result = pow( x, y) ; / * 10000* /

C+ + Tips and Trick s – Part 2 11


D ow nloa de d fr om One Sm a r t Click .Com

Le a r n in g Fr om Com pile r W a r n in gs

The following code has a bug. Can you det ect it ?

DWORD ErrCode= Get Last Error( ) ;


if ( ErrCode ! = ERROR_FI LE_NOT_FOUND) / * warning on t his line* /

Perhaps t he com piler’s warning will give you a clue:

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:

( ( ErrCode) ! = ERROR_FI LE_NOT_FOUND)

I t negat es t he variable ErrCode and t hen com pares it t o t he const ant


ERROR_FI LE_NOT_FOUND. However, t he program m er’s int ent ion was different :

( ! ( ErrCode= = ERROR_FI LE_NOT_FOUND) )

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.

Sh or t - Cir cu it in g St r in g Com pa r ison

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.

D iffe r e n t I n it ia liza t ion For m s Of Obj e ct M e m be r s

Consider t he following class:

C+ + Tips and Trick s – Part 2 12


D ow nloa de d fr om One Sm a r t Click .Com

class A
{
public:
A( int size) ;
privat e:
int size;
};

You can init ialize t he m em ber ’size’ in at least t hree form s:

A: : A ( int size) : size ( size) { }


A: : A ( int size) { t his- > size = size; }
A: : A ( int size) { A: : size = 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

A: : A ( int sz) : size ( sz) { }

Re du n da n t I n lin e D e cla r a t ion s

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

C+ + Tips and Trick s – Part 2 13


D ow nloa de d fr om One Sm a r t Click .Com

{
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;
}

Fr ie n dsh ip An d N e st e d Cla sse s

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 .

M e m be r s W it h D iffe r e n t Acce ss Spe cifie r s

Consider t he following t wo classes:

class A
{
privat e:
int n;
public:
int m ;
};

class B
{
privat e:
int n;

C+ + Tips and Trick s – Part 2 14


D ow nloa de d fr om One Sm a r t Click .Com

int m ;
};

Theoret ically, t he m em ory layout of t hese t wo classes m ay differ because A has


different access t ypes for each m em ber. The C+ + St andard allows an
im plem ent at ion t o st ore such m em bers in nonadj acent m em ory addresses. However,
in pract ice, you can assum e t hat t he t wo classes
have t he sam e m em ory layout .

D iffe r e n ce s Be t w e e n Post fix An d Pr e fix Ope r a t or s

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:

/ * disassem bly of t he expression: m = n+ + ; * /


m ov ecx, [ ebp- 0x04] / * st ore n’s value in ecx regist er* /
m ov [ ebp- 0x08] , ecx / * assign value in ecx t o m * /
inc dword pt r [ ebp- 0x04] / * increm ent n* /

/ * disassem bly of t he expression: m = + + n; * /


inc dword pt r [ ebp- 0x04] / * increm ent n; * /
m ov eax, [ ebp- 0x04] / * st ore n’s value in eax regist er* /
m ov [ ebp- 0x08] , eax / * assign value in eax t o m * /

Poin t e r Con u n dr u m s

C+ + Tips and Trick s – Part 2 15


D ow nloa de d fr om One Sm a r t Click .Com

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) .

Un de r st a n din g St a ck Ove r flow

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* /
}

C+ + Tips and Trick s – Part 2 16


D ow nloa de d fr om One Sm a r t Click .Com

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 algorit hm st d: : fill( ) is declared in < algorit hm > as follows:

void fill( ForwardI t erat or f, ForwardI t erat or l, const T& ) ;

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:

# include < algorit hm >


char * p = new char[ 100] ;
st d: : fill( p, p+ 100, ’\ 0’) ; / * zero all charact ers* /

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:

# include < algorit hm >


# include < vect or >
# include < st ring >

st d: : vect or < st d: : st ring > vs( 100) ;


st d: : fill( vs.begin( ) , vs.end( ) , "greet ings! ") ;

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.

D u plica t e N a m e spa ce Alia se s

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:

nam espace ATL { / * ...* / }


nam espace NS= ATL; / * an alias* /
nam espace NS= ATL; / * OK, duplicat e* /
nam espace NS= NS; / * also OK* /
nam espace NS= st d; / * error* /

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 .

C+ + Tips and Trick s – Part 2 17


D ow nloa de d fr om One Sm a r t Click .Com

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:

t em plat e < class T, void ( T: : * F) ( ) > class callback { / * * / } ;

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( ) :

t em plat e < class T, void ( T: : * F) ( ) >


class callback
{
public:
callback( T& t ) : obj ect ( t ) { } / * assign act ual obj ect t o T* /
void execut e( ) { ( obj ect .* F) ( ) ; } / * launch callback funct ion* /
privat e:
T& obj ect ;
};

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.

Ca llin g A M e m be r Fu n ct ion Th r ou gh A Poin t e r To M e m be r

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:

C+ + Tips and Trick s – Part 2 18


D ow nloa de d fr om One Sm a r t Click .Com

A a; / * creat e obj ect * /


void ( A: : * pm f) ( ) = &A: : f; / * creat e point er t o m em ber* /

/ * t he t wo pairs of parent heses are m andat ory* /


( a.* pm f) ( ) ; / * call funct ion t horough point er t o m em ber* /

Om it t ing t he first pair of parent heses, as in t he following exam ple, is a com m on


m ist ake:

a.* pm f( ) ; / * error, m issing parent heses* /

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:

Dat e get _current _dat e( ) ;

You can avoid t his inefficiency by passing a reference t o t he aggregat e as an


argum ent and writ e t he result int o t hat reference:

void get _current _dat e( Dat e & d) ; / * im proved form * /

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 .

Fix in g A Pot e n t ia l Bu g I n Ct ype Fu n ct ion s

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

C+ + Tips and Trick s – Part 2 19


D ow nloa de d fr om One Sm a r t Click .Com

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

Does your com piler accept t he following code?

char s[ 3] = "abc"; / * illegal; no place for ’\ 0’* /

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:

enum St at { good, bad} ;

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.

C+ + Tips and Trick s – Part 2 20


D ow nloa de d fr om One Sm a r t Click .Com

Bin din g A Re fe r e n ce To An Rva lu e

Binding a reference t o an rvalue is allowed as long as t he reference is bound t o a


const t ype. The rat ionale behind t his rule is st raight forward: you can’t change an
rvalue; only a reference t o const ensures t hat t he program doesn’t m odify an rvalue
t hrough it s reference. I n t he following exam ple, t he funct ion f( ) t akes a reference t o
const int :

void f( const int & i) ;


int m ain( )
{
f( 2) ; / * OK * /
}

The program passes t he rvalue 2 as an argum ent t o f( ) . At runt im e, C+ + creat es a


t em porary obj ect of t ype int wit h t he value 2 and binds it t o t he reference i. The
t em porary and it s reference exist from t he m om ent f( ) is invoked unt il it ret urns;
t hey are dest royed im m ediat ely aft erward. Not e t hat had we declared t he reference i
wit hout t he const qualifier, t he funct ion f( ) could have m odified it s argum ent ,
t hereby causing undefined behavior.

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* /
}

Viola t ion Of An Ex ce pt ion Spe cifica t ion

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* /
}

By default , an at t em pt t o t hrow an except ion of a t ype t hat is not list ed in t he


except ion specificat ion causes t he st d: : unexpect ed( ) funct ion t o be called.
st d: : unexpect ed( ) in t urn calls t erm inat e( ) , which t erm inat es t he program .

Ge t t in g A Pr ogr a m ’s N a m e

C+ + Tips and Trick s – Part 2 21


D ow nloa de d fr om One Sm a r t Click .Com

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:

int m ain( int argc, char* argv[ ] )

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:

int m ain( int argc, char * * argv)


{
cout < < argv[ 0] ; / * nam e of exe file* /
}

Floa t in g- Poin t N u m be r s Re pr e se n t a t ion

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 :

# include < iost ream >


using nam espace st d;
int m ain( )
{
float f1 = 2000.58;
float f2 = 2000.0;
cout < < f1 - f2;
}

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.

Pa ssin g Ar gu m e n t s W it h Side Effe ct 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:

C+ + Tips and Trick s – Part 2 22


D ow nloa de d fr om One Sm a r t Click .Com

char buff[ 12] ;


int n = 0;
/ * second argum ent has a side- effect ; bad idea* /
m em set ( buff, + + n, sizeof( buff) ) ;

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* /

The sam e is t rue for references:

void f( B & b) ; / * b’s st at ic t ype is B&* /


D d;
f( d) ; / * argum ent ’s dynam ic t ype is D&* /

D iffe r e n ce s Pr ot ot ype s Of St a n da r d Fu n ct ion s

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:

char* st rst r( const char* s1, const char* s2) ; / * ANSI C* /

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:

char* st rst r( char* s1, const char* s2) ; / * ANSI C+ + * /


const char * st rst r( const char* s1, const char* s2) ; / * ANSI C+ + * /

Anot her exam ple: t he funct ion st rpbrk( ) . I n C, it has t his signat ure:

char* st rpbrk( const char* s1, const char* s2) ; / * ANSI C* /

I n C+ + , it has t wo different signat ures:

char* st rpbrk( char* s1, const char* s2) ; / * ANSI C+ + * /


const char* st rpbrk( const char* s1, const char* s2) ; / * ANSI C+ + * /

C+ + Tips and Trick s – Part 2 23


D ow nloa de d fr om One Sm a r t Click .Com

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:

* A num eric lit eral, as 100 in

x < 100;

* Enum erat ors such as up and down in t he following enum t ype:

enum st at e { up, down} ;

* 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:

S < 100 > s;

* Finally, a sizeof expression:

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

Do t he following declarat ions differ in any way from each ot her?

C+ + Tips and Trick s – Part 2 24


D ow nloa de d fr om One Sm a r t Click .Com

const long int N= 0;


long const int N= 0;

No, t hey don’t . C+ + doesn’t enforce a specific order of t ype qualifiers in a


declarat ion. Therefore, you can use any perm ut at ion wit hout changing t he
declarat ion’s sem ant ics. I n bot h cases, t he com piler builds t he sam e int ernal t ree
and produces t he sam e assem bly code and m angled nam es for funct ions.

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:

int l= 10, m = 11, n= 7;


int highest = m ax( l,m ax( n,m ) ) ;

Re fe r r in g To Cla ss- I n t e r n a l Type s

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:

sizes A: : default _size( ) const


{
ret urn m edium ;
}

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:

A: : sizes A: : default _size( ) const


{
ret urn m edium ;
}

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.

C+ + Tips and Trick s – Part 2 25


D ow nloa de d fr om One Sm a r t Click .Com

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

int _fast 8_t int _fast 16_t


int _fast 32_t int _fast 64_t

Their unsigned count erpart s are

uint _fast 8_t uint _fast 16_t


uint _fast 32_t uint _fast 64_t

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:

# include < int t ypes.h >


int _fast 16_t n;
for ( n= 0; n < 1000; + + n)
{
/ / ..
}

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 * /

C+ + Tips and Trick s – Part 2 26


D ow nloa de d fr om One Sm a r t Click .Com

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

You can allocat e m ult idim ensional arrays m anually, as in

int ( * ppi) [ 5] = new int [ 4] [ 5] ; / * parent heses required* /


/ * fill array..* /
ppi[ 0] [ 0] = 65;
ppi[ 0] [ 1] = 66;
ppi[ 0] [ 2] = 67;
/ / ..

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:

# include < vect or >


# include < iost ream >
using nam espace st d;
int m ain( )
{
vect or < vect or < int > > v; / * t wo dim ensions* /
v.push_back( vect or < int > ( ) ) ; / * creat e v[ 0] * /
v.push_back( vect or < int > ( ) ) ; / * creat e v[ 1] * /
v[ 0] .push_back( 15) ; / * assign v[ 0] [ 0] * /
v[ 1] .push_back( 16) ; / * assign v[ 1] [ 0] * /

C+ + Tips and Trick s – Part 2 27


D ow nloa de d fr om One Sm a r t Click .Com

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:

cout < < v[ 0] [ 0] ;


cout < < v[ 1] [ 0] ;

A Sh or t h a n d For I n t e r n a t ion a liza t ion

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.

Acce ssin g M e m be r s W it h St a t ic M e m be r Fu n ct ion s

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;
};

Singlet on * Singlet on: : inst ance( )


{
if ( lock.used) / * OK, lock is a st at ic m em ber* /
/ / ..
}

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:

void C: : func( C & obj ) / * a st at ic m em ber funct ion* /


{
int n = obj .get _x( ) ; / * access a m em ber t hrough reference* /
}

C+ + Tips and Trick s – Part 2 28


D ow nloa de d fr om One Sm a r t Click .Com

Fa h r e n h e it To Ce lsiu s Con ve r sion

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:

double t o_celsius( double fahr)


{
ret urn 5.0/ 9.0* ( fahr- 32.0) ;
}

double t o_fahrenheit ( double cel)


{
ret urn 9.0/ 5.0* cel+ 32.0;
}

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:

# include < lim it s >


using st d: : num eric_lim it s;
int m ain( )
{
int n;
n= num eric_lim it s < float > : : digit s10; / * 6 on m y m achine* /
n= num eric_lim it s < double > : : digit s10; / * 15* /
n= num eric_lim it s < long > : : digit s10; / * 9* /
}

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:

ext ern void func( int i) ; / * ext ern is redundant * /

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:

/ * found in < st ring.h > * /


ext ern size_t st rlen( const char * s) ;

C+ + Tips and Trick s – Part 2 29


D ow nloa de d fr om One Sm a r t Click .Com

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.

Ca llin g Ove r loa de d Ope r a t or s Ex plicit ly

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

cout < < "hello world";

can be rewrit t en as follows:

cout .operat or< < ( "hello world") ;

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= = "") ;

you can writ e

em pt y = s.operat or= = ( "") ; / * com pare * p t o an em pt y st ring* /

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:

# include < ft sream >


int m ain( )
{
st d: : ifst ream in ( "oldfile.t xt ") ; / * open original file* /
st d: : ofst ream out ( "newfile.t xt ") ; / * open t arget file* /
out < < in.rdbuf( ) ; / * read original file int o t arget * /
out .close( ) ; / * explicit close, opt ional* /
in.close( ) ; / * explicit close, opt ional* /
}

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

C+ + Tips and Trick s – Part 2 30


D ow nloa de d fr om One Sm a r t Click .Com

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.

Poin t e r Con t a in e r s An d Efficie n cy

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:

st d: : vect or < st d: : st ring > v;


v.reserve( 1000) ; / * m ake room for at least 1000 st rings* /

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* /

use t he # undef preprocessor direct ive t o cancel a previously defined m acro:

# include "defs.h"
# undef PI / * from now on, ignore t he PI m acro* /
const double PI = 3.14159265358979 / * OK* /

Pr e fix Ope r a t or s An d Use r - D e fin e d Type s

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

C+ + Tips and Trick s – Part 2 31


D ow nloa de d fr om One Sm a r t Click .Com

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:

st ring: : it erat or si;


si= s.begin( ) ;
si+ + ; / * probably less efficient t han + + si* /

Therefore, always prefer prefix operat ors t o post fix ones when you can choose
bet ween t he t wo.

Sh or t h a n d For Assign m e n t Ope r a t ion s

For recursive assignm ent expressions such as t hese:

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* /

C+ + Tips and Trick s – Part 2 32


D ow nloa de d fr om One Sm a r t Click .Com

Re du cin g Com pila t ion Tim e

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.

St a ck Un w in din g I n Th e Eve n t Of An Un ca u gh t Ex ce pt 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.

Cou n t in g " Live " I n st a n ce s Of A Cla ss

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 ; }
};

int A: : count ; / * st at ic m em ber definit ion* /

C+ + Tips and Trick s – Part 2 33


D ow nloa de d fr om One Sm a r t Click .Com

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:

# include < iost ream >


using st d: : cerr;
if ( failed)
{
cerr < < "call syst em adm inist rat or"; / * no endl needed* /
}

Sw a ppin g Tw o I n t e ge r s W it h ou t Usin g A Te m por a r y

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:

void swap( int & i, int & j )


{
i ^ = j;
j ^ = i;
i ^ = j;
} / * i and j are swapped* /

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;

C+ + Tips and Trick s – Part 2 34


D ow nloa de d fr om One Sm a r t Click .Com

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 .

Equ iva le n ce I n STL

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 :

bool operat or= = ( const T & arg1, const T & arg2)


{
ret urn ( ! ( arg1 < arg2) ) && ( ! ( arg1 < arg2) )
}

I n ot her words, you don’t need t o define an overloaded version of operat or = = ( or


any ot her relat ional operat or) because STL knows how t o generat e t hese operat ors
from operat or < . Therefore, you only need t o define an overloaded version of
operat or < for user- defined t ypes.

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:

include < st dio.h >


int m ain( )
{
int st at = renam e( "backup.dat ", "backup.old") ;
if ( st at )
{
/ * ..renam e failed* /
}
}

On success, renam e( ) ret urns zero; ot herwise, it ret urns a code indicat ing t he error
t ype.

I ost r e a m An d Com ple x N u m be r s

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:

# include < com plex >

C+ + Tips and Trick s – Part 2 35


D ow nloa de d fr om One Sm a r t Click .Com

# include < iost ream >


using nam espace st d;

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:

- - I t reduces t he program ’s size because t he library’s code is not included in


t he program ’s execut able file

- - Changes m ade t o t he runt im e library, such as an upgrade or bug fixes,


don’t require t hat t he program s be relinked; t he next t im e you run t he
program , it aut om at ically loads t he new library version and accesses it s code
and dat a.

- - A dynam ic library saves considerable am ount of disk space because it s


code is shared rat her t han being copied int o each program file.

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.

C+ + Tips and Trick s – Part 2 36


D ow nloa de d fr om One Sm a r t Click .Com

Ca ch e Th e Re su lt Of Com ple x Com pu t a t ion s

The following loop is very inefficient :

for ( int j = 0; j < st rlen( s) ; + + j )


{
/ * .. do som et hing* /
}

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:

const int lengt h = st rlen( s) ; / * cache t he result * /


for ( int j = 0; j < lengt h; + + j ) / * use cached value* /
{
/ * .. do som et hing* /
}

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.

Opt im izin g M e m be r Align m e n t

The size of class can be changed sim ply by playing wit h t he order of it s m em bers’
declarat ion:

C+ + Tips and Trick s – Part 2 37


D ow nloa de d fr om One Sm a r t Click .Com

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) .

D e cla r in g A Te m pla t e Spe cia liza t ion As A Fr ie n d Of A Cla ss Te m pla t e

You can declare a t em plat e specializat ion as a friend 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 specializat ion C < void* >
as it s friend:

t em plat e < class T > class C{ / * ...* / } ;


t em plat e < class T > class Vect or
{
public:
/ / ...
friend class C < void* > ; / * ot her specializat ions of C are NOT
friends of Vect or* /
};

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.

D e cla r in g N on - Te m pla t e Fu n ct ion s An d Cla sse s As Te m pla t e Fr ie n ds

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:

C+ + Tips and Trick s – Part 2 38


D ow nloa de d fr om One Sm a r t Click .Com

class Thing { / * ..* / } ;


t em plat e < class T > class Vect or
{
public:
friend void f ( ) ; / * non- t em plat e funct ion
friend class Thing; / * non- t em plat e class* /
};
Vect or < int > vi;
Vect or < st ring > vs;

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:

# include < iost ream >


# include < vect or >
# include < st ring >
using nam espace st d;
void ascending_order( vect or < double > &v)
{
vect or < double > : : reverse_it erat or rp = v.rbegin( ) ;
/ * display elem ent s in ascending order* /
while ( rp < v.rend( ) )
{
cout < < * rp < < ’\ n’;
+ + rp;
}
}

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:

# include < algorit hm > / * definit ion of find( ) * /


# include < list >
# include < iost ream >

C+ + Tips and Trick s – Part 2 39


D ow nloa de d fr om One Sm a r t Click .Com

using nam espace st d;


int m ain( )
{
list < char > lc;
lc.push_back( ’A’) ;
lc.push_back( ’T’) ;
lc.push_back( ’L’) ;

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:

cat ch ( st d: : bad_alloc & new_failure)


{
/ * handle st d: : bad_alloc* /
}
cat ch ( st d: : except ion & exc)
{
/ * handle st d: : except ion and derived except ions except nad_alloc* /
}

The st andard except ions t hrown by built - in operat ors of t he language are

st d: : bad_alloc / * t hrown by operat or new* /


st d: : bad_cast / * t hrown by dynam ic_cast * /
st d: : bad_t ypeid / * m ay be t hrown by t ypeid* /
st d: : bad_except ion / * t hrown when an except ion specificat ion is violat ed* /

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.

Ex ce pt ion Spe cifica t ion s Ar e Ch e ck e d At Ru n t im e

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 f( ) ; / * can t hrow any t ype of except ion* /


void g( int j ) t hrow( ) ; / * prom ises not t o t hrow any except ion* /

C+ + Tips and Trick s – Part 2 40


D ow nloa de d fr om One Sm a r t Click .Com

{
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.

M AKI N G I N LI N E FUN CTI ON S COM PATI BLE W I TH C COM PI LERS

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 :

enum Direct ion ( West , Nort h East , Sout h} ;


Direct ion d;
d = 1; / * OK in C, d equals ’Nort h’ * /

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:

d = st at ic_cast < Direct ion > ( 1) ; / / fine


d = East ;

C+ + Tips and Trick s – Part 2 41


D ow nloa de d fr om One Sm a r t Click .Com

Use D e r iva t ion I n st e a d Of Type - Fie lds

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
{
/ / ...

C+ + Tips and Trick s – Part 2 42


D ow nloa de d fr om One Sm a r t Click .Com

}
};

class B: public A / * bad; inherit ing a non virt ual dt or* /


{
public:
~ B( )
{
/ / ...
}
};

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:

bool binary_search ( ForwardI t erat or first ,


ForwardI t erat or last ,
const T& value)

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:

# include < algorit hm >


# include < vect or >
using nam espace st d;
int m ain( )
{
int arr[ 5] = { 1,3,4,5,5} ;
/ * set a vect or from t he array * /
vect or < int > vi( arr, arr+ 5) ;
/ * search for 5 and 0 in t he vect or * /
bool found = binary_search( vi.begin( ) , vi.end( ) , 5) ; / * t rue* /
found = binary_search( vi.begin( ) , vi.end( ) , 0) ; / * false* /
}

FORW ARD - D ECLARI N G I / O CLASSES AN D TEM PLATES

C+ + Tips and Trick s – Part 2 43


D ow nloa de d fr om One Sm a r t Click .Com

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:

# include < iosfwd >


using nam espace st d;
class C
{
public:
friend ost ream & operat or < < ( ost ream & os, const C & d) ;
};
ost ream & operat or < < ( ost ream & os, const C & d) ;

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.

OVERLOAD I N G N EW AN D D ELETE FOR A CLASS

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.

I n t he following exam ple, class C overloads operat or new t o alt er t he default


behavior in t he event of an allocat ion failure; inst ead of t hrowing st d: : bad_alloc, t his
specific version t hrows const char * . A m at ching operat or delet e is also defined:

# include < cst dlib > / * m alloc( ) and free( ) * /


# include < iost ream >
using nam espace st d;
class C
{
public:
void* operat or new ( size_t size) ;
void operat or delet e ( void * p) ;
};

void* C: : operat or new ( size_t size) t hrow ( const char * )


{
void * p = m alloc( size) ;
if ( p = = 0)
t hrow "allocat ion failure"; / * inst ead of st d: : bad_alloc * /
ret urn p;

C+ + Tips and Trick s – Part 2 44


D ow nloa de d fr om One Sm a r t Click .Com

void C: : operat or delet e ( void * p)


{
free( p) ;
}

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.

SOM E QUI ET D I FFEREN CES BETW EEN C AN D C+ +

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.

I n C, t he size of an enum t ype is t he sam e as t he size of an int . I n C+ + , t here is no


such guarant ee: The size of an enum m ay be larger or sm aller t han t he size of an
int .

I n C, t he result of applying operat or sizeof t o a charact er const ant , as in t he


expression sizeof( ’c’) , is equivalent t o sizeof( int ) . I n C+ + , on t he ot her hand, t he
expression sizeof( ’c’) is equivalent t o sizeof( char) .

STRI N G LI TERALS AN D TEM PLATE ARGUM EN TS

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:

t em plat e < class T, const char * > class A


{ / * ...* / } ;
ext ern const char * global_pt r;
void array_user( )
{
const char * p = "illegal";
A < int , "invalid" > aa; / * error, st ring lit eral used as argum ent * /
A < int , p > ab; / * error, p has int ernal linkage * /
A < int , global_pt r > ac; / * OK, global_pt r has ext ernal linkage * /
}

W H AT ARE LVALUES AN D RVALUES?

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

C+ + Tips and Trick s – Part 2 45


D ow nloa de d fr om One Sm a r t Click .Com

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:

# include < st ring >


using nam espace st d;
int & f( ) ;
void func( )
{
int n;
char buf[ 3] ;
n = 5; / * n is an lvalue; 5 is an rvalue * /
buf[ 0] = ’a’; / * buf[ 0] is an lvalue, ’a’ is an rvalue * /
st ring s1 = "a", s2 = "b", s3 = "c"; / * "a", "b", "c" are rvalues * /
s1 = / * lvalue * /
s2 + s3;
/ * s2 and s3 are lvalues t hat are im plicit ly convert ed t o rvalues * /
s1 =
st ring( "z") ; / * t em poraries are rvalues * /
int * p = new int ; / * p is an lvalue; ’new int ’ is an rvalue * /
f( ) = 0; / * a funct ion call t hat ret urns a reference is an lvalue * /
s1.size( ) ; / * ot herwise, a funct ion call is an rvalue expression * /
}

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.

TH E " BI G TH REE RULE" VERSUS TH E " BI G TW O RULE"

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;

C+ + Tips and Trick s – Part 2 46


D ow nloa de d fr om One Sm a r t Click .Com

}
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.

SOM E D ESI GN AN D COD I N G RULE OF TH UM BS

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;

Then, precede t he keyword "t ypedef" t o t he previous declarat ion:

t ypedef 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:

C+ + Tips and Trick s – Part 2 47


D ow nloa de d fr om One Sm a r t Click .Com

int ( * pfi) ( int ) ;

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:

t ypedef int ( * pfi) ( int ) ;

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:

int func( int ) ;


void callback( pfi som e_func)
{
int result = som e_func( 5) ;
}

TH E LI N KAGE TYPE OF GLOBAL CON ST OBJECTS

I n C+ + ( but not in C) , a const obj ect declared in t he global scope has


int ernal linkage. This m eans t hat a const obj ect t hat apparent ly looks
like a global one is visible only in t he scope of it s source file; it
isn’t visible from ot her files unless you explicit ly declare it
ext ern:

/ * 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:

Public sym bol x defined in bot h m odule a.obj and b.obj

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;

C+ + Tips and Trick s – Part 2 48


D ow nloa de d fr om One Sm a r t Click .Com

This is bot h redundant and deprecat ed.

D ON ’T CON FUSE D ELETE W I TH D ELETE[ ]

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,

int * p = new int [ 10] ;


delet e p; / * bad; should be: delet e[ ] p * /

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.

STATI C I N I TI ALI ZATI ON AN D D YN AM I C I N I TI ALI ZATI ON

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( )
{
}

The global variable x has st at ic st orage. Therefore, it ’s init ialized t o 0 at t he st at ic


init ializat ion phase ( by default , obj ect s wit h st at ic st orage are zero- init ialized) . The
subsequent dynam ic init ializat ion phase init ializes x wit h t he value ret urned from t he
funct ion func( ) . This operat ion can t ake place only at runt im e.

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.

CORRECTLY D ECLARI N G GLOBAL OBJECTS

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.

C+ + Tips and Trick s – Part 2 49


D ow nloa de d fr om One Sm a r t Click .Com

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
/* * * * * * * * * /

/ * declarat ion only; x is defined in anot her file* /


ext ern int x;

st ruct Count er
{
Count er( ) { + + x; }
~ Count er( ) { - - x; }
};

/ / File b.cpp
/* * * * * * * * * /

int x; / * definit ion of a global variable * /

/ / 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.

PREFER STL CON TAI N ERS TO H OM EM AD E ON ES

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.

M I SSI N G H EAD ER FI LES

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

C+ + Tips and Trick s – Part 2 50


D ow nloa de d fr om One Sm a r t Click .Com

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.

I N TEGERS W I TH PLATFORM - I N D EPEN D EN T W I D TH

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:

int 8_t int 16_t int 32_t int 64_t

And t heir unsigned count erpart s are

uint 8_t uint 16_t uint 32_t uint 64_t

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 .

RED UCI N G A CLASS’S SI ZE

C+ + Tips and Trick s – Part 2 51


D ow nloa de d fr om One Sm a r t Click .Com

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;
};

On m y m achine, class Bloat ed occupies 16 byt es. Slim , on t he ot her


hand, occupies only 4 byt es.

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:

# include < cst dio >


# include < iost ream >
using nam espace st d;
int m ain( )
{
st ring nam e;
/ / ...get file nam e
int st at = rem ove( nam e.c_st r( ) ) ;
if ( st at )
cout < < "failed t o delet e file";
}

ASSI GN I N G A SPECI FI ED M EM ORY AD D RESS TO A POI N TER

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* /

C+ + Tips and Trick s – Part 2 52


D ow nloa de d fr om One Sm a r t Click .Com

p = reint erpret _cast < void* > ( 0x5800FF) ;

D I SABLI N G COPYI N G AN D ASSI GN M EN T OF AN OBJECT

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

Does your com piler accept t he following declarat ions?

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:

volat ile int x;


const int y = 0;

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.

PASS TEM PLATE PARAM ETERS EFFI CI EN TLY

I n t he following declarat ion of t he t em plat e m in, t he t em plat e


param et er T is passed by value:

C+ + Tips and Trick s – Part 2 53


D ow nloa de d fr om One Sm a r t Click .Com

t em plat e < class T > bool equal( T first , T sec)


{
/ / ...
}

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) ;

I f t he t em plat e isn’t allowed t o change it s argum ent s, declare t hem as const


param et ers:

t em plat e < class T > bool equal ( const T& first ,


const T& sec) ;

LI N KAGE SPECI FI CATI ON

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:

ext ern "Ada" int func( int arg1) ; / * Ada linkage* /


ext ern "Fort ran" int func( int arg1) ; / * Fort ran linkage* /

CALCULATI N G TI M E D I FFEREN CES

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:

# include < ct im e >


# include < iost ream >
using nam espace st d;
int m ain( )
{
t im e_t now = t im e( 0) ; / * current t im e* /
t im e_t last _week = now - ( 60* 60* 24* 7) ;
double seconds = difft im e( now, last _week) ;
cout < < seconds < < " have elapsed since last week";
}

C+ + Tips and Trick s – Part 2 54


D ow nloa de d fr om One Sm a r t Click .Com

PREFER STRI N GSTREAM TO STRSTREAM

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) :

ost rst ream s; / * deprecat ed* /


float f = 6.6777;
s < < f; / * insert f int o t he st ream * /
st ring st = s.st r( ) ; / * copy int o a st ring* /

should be rewrit t en as follows:

st d: : ost ringst ream s;


float f = 6.6777;
s < < f;
st d: : st ring st = s.st r( ) ;

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.

RE- EN TRAN T FUN CTI ON S

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.

CALLI N G A FUN CTI ON BEFORE PROGRAM ’S STARTUP

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

C+ + Tips and Trick s – Part 2 55


D ow nloa de d fr om One Sm a r t Click .Com

{
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

Many program m ers use t he endl m anipulat or excessively, as in

cout < < "user login" < < endl;


cout < < "ent er your nam e: " < < endl;
cin > > nam e;

I n t he first line, t he endl m anipulat or is added t o force a line break. However, it ’s


cheaper in t erm s of perform ance t o use t he \ n charact er inst ead of endl because endl
also flushes t he st ream rat her t han j ust adding a line break. Flushing a st ream can
be a cost ly operat ion. The second cout expression, t oo, has a redundant endl
m anipulat or. I n any event , t he out put m ust appear on t he screen before t he cin
expression is execut ed because cin and cout are t ied.

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

cout < < "ent er your nam e: ";


cin > > nam e;

C+ + ensures t hat cout displays t he m essage on t he screen before cin prepares t o


accept input , even if you don’t use an explicit flush operat ion or t he endl
m anipulat or.

C+ + Tips and Trick s – Part 2 56


D ow nloa de d fr om One Sm a r t Click .Com

TRAN SFORM I N G A STRI N G TO UPPERCASE

To change t he case of a st ring obj ect , use t he st d: : t ransform ( ) algorit hm . This


algorit hm is defined in t he st andard header < algorit hm > . I t t akes four argum ent s.
The first t wo argum ent s are input it erat ors t hat m ark t he beginning and t he end of
t he st ring, respect ively. The t hird argum ent is an out put it erat or point ing t o t he
beginning of t he original st ring ( t he uppercase version of t he st ring is writ t en ont o
t he original st ring) . The fourt h argum ent is an obj ect t hat support s t he ( ) operat or
and t akes one argum ent . I t can be a funct ion point er or a funct ion obj ect .
t ransform ( ) uses t he fourt h argum ent t o m anipulat e every elem ent in t he sequence.
I n our exam ple, we pass t he address of t he st andard funct ion t oupper( ) defined in
t he header < cct ype > :

# include < algorit hm >


# include < st ring >
# include < iost ream >
# include / * for t oupper( ) * /

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 * /

st d: : cout < < s; / * display "HELLO" * /


}

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 :

st d: : t ransform ( s.begin( ) , s.end( ) , s2.begin( ) ,


st at ic_cast < int ( * ) ( int ) > ( t oupper) ) ;

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

C+ + Tips and Trick s – Part 2 57


D ow nloa de d fr om One Sm a r t Click .Com

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:

st ring: : it erat or it = s.begin( ) ;


char c = * ( it + 5) ; / * assign fift h char t o c* /

AVOI D I N G M EM ORY FRAGM EN TATI ON

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.

USI N G D EFAULT TYPE PARAM ETERS I N TEM PLATES

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:

C+ + Tips and Trick s – Part 2 58


D ow nloa de d fr om One Sm a r t Click .Com

t em plat e < class T1= char, class T2= char >


class E
{
public:
E( T1 t 1, T2 t 2 ) { m 1= t 1; m 2= t 2; }
privat e:
T1 m 1;
T2 m 2;
};

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 * /
}

CREATI N G I M M UTABLE CON STAN TS

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 :

const int MAX= 512;

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:

int * p = const _cast < int * > ( & MAX) ;


* p= 100; / * at t em pt t o change MAX t hrough a point er* /

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 :

# define MAX 512

This t im e, MAX can’t be changed.

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
{

C+ + Tips and Trick s – Part 2 59


D ow nloa de d fr om One Sm a r t Click .Com

signed char a: 2; / * possible values: - 1,0 1* /


unsigned signed char b: 1; / * values: 0,1 * /
};

REM OVE UN N ECESSARY # I N CLUD ES

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

CALCULATI N G TH E SI ZE OF AN I N COM PLETE ARRAY

An incom plet e array declarat ion can appear in a funct ion’s param et er list . For
exam ple:

int count ( const char s[ ] ) ;

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:

int count ( const char s[ ] , int arr_size) ;

However, a bet t er solut ion is t o pass a vect or and call it s size( ) m em ber funct ion:

int cout ( const vect or < char > & s )

C+ + Tips and Trick s – Part 2 60


D ow nloa de d fr om One Sm a r t Click .Com

{
ret urn s.size( ) ;
}

D ECLARI N G VARI ABLES I N SI D E AN I F- CON D I TI ON

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 :

class Base { / * ..* / } ;


class Derived: public Base { / * ..* / } ;
void func ( Base & b)
{
/ * pd is declared inside if- condit ion* /
if ( Derived * pd = dynam ic_cast < Derived* > ( & b) )
{
/ * dynam ic_cast was successful; use pd here* /
ret urn;
} / * pd goes out of scope at t his point * /
/ * ot herwise dynam ic_cast failed; variable pd is not in scope* /
}

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 .

AVOI D ASSI GN M EN TS I N SI D E AN I F CON D I TI ON

An assignm ent expression can appear inside an if condit ion:

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.

C+ + Tips and Trick s – Part 2 61


D ow nloa de d fr om One Sm a r t Click .Com

REVERSI N G OPERAN D S’ ORD ER I N AN EQUALI TY EXPRESSI ON

An equalit y expression t akes t wo operands, t he second of which is oft en a const ant


or an rvalue:

if ( x= = 4) / * 4 is an rvalue* /
...
if ( y! = MAX_COUNT) / * MAX_COUNT is a const ant * /
...

Som e program m ers prefer t o reverse t he operands’ order:

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:

if ( 4= X) / * m ist akenly used = inst ead of = = * /


/ * .. do som et hing * /

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 .

LI N KAGE TYPE OF TYPED EF N AM ES

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 first .cpp * /


t ypedef int I ; / * visible only in t he scope of t his file *
void func( I ) ;

/ * file second.cpp * /
t ypedef int I ; / * visible only in t he scope of t his file * /
float func2( I ) ;

C+ + Tips and Trick s – Part 2 62


D ow nloa de d fr om One Sm a r t Click .Com

A REFEREN CE TO A REFEREN CE I S I LLEGAL

What is wrong wit h t his code snippet ?

# include < st ring >


# include < list >
using st d: : st ring;
using st d: : list ;

class Node { / * ..* / } ;

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 &
>.

ARGUM EN TS AN D PARAM ETERS

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.

An argum ent is one of t he following:

- an expression in t he com m a- separat ed list in a funct ion call


- a sequence of one or m ore preprocessor t okens in t he com m a- separat ed list in a
m acro call
- t he operand of a t hrow- st at em ent
- an expression, t ype, or t em plat e- nam e in t he com m a- separat ed list in t he angle
bracket s of a t em plat e inst ant iat ion.

An argum ent is som et im es called an "act ual param et er."

A param et er is one of t he following:


- an obj ect or reference t hat is declared in a funct ion declarat ion or definit ion
- an ident ifier bet ween t he parent heses im m ediat ely following t he
m acro nam e in a m acro definit ion
- a t em plat e- param et er

A param et er is som et im es called a "form al param et er."

C+ + Tips and Trick s – Part 2 63


D ow nloa de d fr om One Sm a r t Click .Com

The following exam ple dem onst rat es t he difference bet ween a param et er and an
argum ent :

void func( int n, char * pc) ; / * n and pc are param et ers * /


t em plat e &< class T &> class A{ } ; / * T is a a param et er * /

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.

What is wrong wit h t his code snippet ?

# include &< st ring &>


# include &< list &>
using st d: : st ring;
using st d: : list ;

class Node { / * ..* / } ;

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 &&> .

More docum ent s like t his:

On e Sm a r t Click .Com

C+ + Tips and Trick s – Part 2 64

Das könnte Ihnen auch gefallen