Tải bản đầy đủ - 0 (trang)
Item 2: Prefer <iostream> to <stdio.h>

Item 2: Prefer <iostream> to <stdio.h>

Tải bản đầy đủ - 0trang

Trythatusingscanfandprintf!

Here'showyoumightwriteanoutputroutineforaclassrepresentingrational

numbers:

classRational{

public:

Rational(intnumerator=0,intdenominator=1);

...

private:

intn,d;//numeratoranddenominator

friendostream&operator<<(ostream&s,constRational&r);

};

ostream&operator<<(ostream&s,constRational&r)

{

s<
returns;

}



Thisversionofoperator<
arediscussedelsewhereinthisbook.Forexample,operator<
function(Item19explainswhy),andtheRationalobjecttobeoutputispassed

intooperator<
Thecorrespondinginputfunction,operator>>,wouldbedeclaredand

implementedinasimilarmanner.

ReluctantthoughIamtoadmitit,therearesomesituationsinwhichitmay

makesensetofallbackonthetriedandtrue.First,someimplementationsof

iostreamoperationsarelessefficientthanthecorrespondingCstream

operations,soit'spossible(thoughunlikely—seeItemM16)thatyouhavean

applicationinwhichthismakesasignificantdifference.Bearinmind,though,

thatthissaysnothingaboutiostreamsingeneral,onlyaboutparticular

implementations;seeItemM23.Second,theiostreamlibrarywasmodifiedin

someratherfundamentalwaysduringthecourseofitsstandardization(seeItem

49),soapplicationsthatmustbemaximallyportablemaydiscoverthatdifferent

vendorssupportdifferentapproximationstothestandard.Finally,becausethe

classesoftheiostreamlibraryhaveconstructorsandthefunctionsin

donot,therearerareoccasionsinvolvingtheinitializationorderofstaticobjects

(seeItem47)whenthestandardClibrarymaybemoreusefulsimplybecause



youknowthatyoucanalwayscallitwithimpunity.

Thetypesafetyandextensibilityofferedbytheclassesandfunctionsinthe

iostreamlibraryaremoreusefulthanyoumightinitiallyimagine,sodon'tthrow

themawayjustbecauseyou'reusedto.Afterall,evenafterthe

transition,you'llstillhaveyourmemories.

Incidentally,that'snotypointheItemtitle;Ireallymeanandnot

.Technicallyspeaking,thereisnosuchthingas

the standardizationcommitteeeliminateditinfavorofwhenthey

truncatedthenamesoftheothernon-Cstandardheadernames.Thereasonsfor

theirdoingthisareexplainedinItem49,butwhatyoureallyneedtounderstand

isthatif(asislikely)yourcompilerssupportbothand

,theheadersaresubtlydifferent.Inparticular,ifyou#include

,yougettheelementsoftheiostreamlibraryensconcedwithinthe

namespacestd(seeItem28),butifyou#include,yougetthose

sameelementsatglobalscope.Gettingthematglobalscopecanleadtoname

conflicts,preciselythekindsofnameconflictstheuseofnamespacesis

designedtoprevent.Besides,islesstotypethan.For

manypeople,that'sreasonenoughtopreferit.

°



BacktoItem1:Preferconstandinlineto#define.

ContinuetoItem3:Prefernewanddeletetomallocandfree.



BacktoItem2:Preferto.

ContinuetoItem4:PreferC++-stylecomments.



Item3:Prefernewanddeletetomallocandfree.

Theproblemwithmallocandfree(andtheirvariants)issimple:theydon't

knowaboutconstructorsanddestructors.

Considerthefollowingtwowaystogetspaceforanarrayof10stringobjects,

oneusingmalloc,theotherusingnew:

string*stringArray1=

static_cast(malloc(10*sizeof(string)));

string*stringArray2=newstring[10];



HerestringArray1pointstoenoughmemoryfor10stringobjects,butno

objectshavebeenconstructedinthatmemory.Furthermore,withoutjumping

throughsomeratherobscurelinguistichoops(suchasthosedescribedinItems

M4andM8),youhavenowaytoinitializetheobjectsinthearray.Inother

words,stringArray1isprettyuseless.Incontrast,stringArray2pointstoan

arrayof10fullyconstructedstringobjects,eachofwhichcansafelybeusedin

anyoperationtakingastring.

Nonetheless,let'ssupposeyoumagicallymanagedtoinitializetheobjectsinthe

stringArray1array.Lateroninyourprogram,then,you'dexpecttodothis:

free(stringArray1);

delete[]stringArray2;//seeItem5forwhythe

//"[]"isnecessary



ThecalltofreewillreleasethememorypointedtobystringArray1,butno

destructorswillbecalledonthestringobjectsinthatmemory.Ifthestring

objectsthemselvesallocatedmemory,asstringobjectsarewonttodo,allthe

memorytheyallocatedwillbelost.Ontheotherhand,whendeleteiscalledon

stringArray2,adestructoriscalledforeachobjectinthearraybeforeany

memoryisreleased.

Becausenewanddeleteinteractproperlywithconstructorsanddestructors,they

areclearlythesuperiorchoice.



Mixingnewanddeletewithmallocandfreeisusuallyabadidea.Whenyou

trytocallfreeonapointeryougotfromneworcalldeleteonapointeryougot

frommalloc,theresultsareundefined,andweallknowwhat"undefined"

means:itmeansitworksduringdevelopment,itworksduringtesting,andit

blowsupinyourmostimportantcustomers'faces.

Theincompatibilityofnew/deleteandmalloc/freecanleadtosomeinteresting

complications.Forexample,thestrdupfunctioncommonlyfoundin

takesachar*-basedstringandreturnsacopyofit:

char*strdup(constchar*ps);//returnacopyofwhat

//pspointsto



Atsomesites,bothCandC++usethesameversionofstrdup,sothememory

allocatedinsidethefunctioncomesfrommalloc.Asaresult,unwittingC++

programmerscallingstrdupmightoverlookthefactthattheymustusefreeon

thepointerreturnedfromstrdup.Butwait!Toforestallsuchcomplications,

somesitesmightdecidetorewritestrdupforC++andhavethisrewritten

versioncallnewinsidethefunction,therebymandatingthatcallerslateruse

delete.Asyoucanimagine,thiscanleadtosomeprettynightmarishportability

problemsascodeisshuttledbackandforthbetweensiteswithdifferentformsof

strdup.

Still,C++programmersareasinterestedincodereuseasCprogrammers,and

it'sasimplefactthattherearelotsofClibrariesbasedonmallocandfree

containingcodethatisverymuchworthreusing.Whentakingadvantageofsuch

alibrary,it'slikelyyou'llendupwiththeresponsibilityforfreeingmemory

mallocedbythelibraryand/ormallocingmemorythelibraryitselfwillfree.

That'sfine.There'snothingwrongwithcallingmallocandfreeinsideaC++

programaslongasyoumakesurethepointersyougetfrommallocalwaysmeet

theirmakerinfreeandthepointersyougetfromneweventuallyfindtheirway

todelete.Theproblemsstartwhenyougetsloppyandtrytomixnewwithfree

ormallocwithdelete.That'sjustaskingfortrouble.

Giventhatmallocandfreeareignorantofconstructorsanddestructorsandthat

mixingmalloc/freewithnew/deletecanbemorevolatilethanafraternityrush

party,you'rebestoffstickingtoanexclusivedietofnewsanddeleteswhenever

youcan.

BacktoItem2:Preferto.



ContinuetoItem4:PreferC++-stylecomments.



BacktoItem3:Prefernewanddeletetomallocandfree.

ContinuetoMemoryManagement



Item4:PreferC++-stylecomments.

ThegoodoldCcommentsyntaxworksinC++too,butthenewfangledC++

comment-to-end-of-linesyntaxhassomedistinctadvantages.Forexample,

considerthissituation:

if(a>b){

//inttemp=a;//swapaandb

//a=b;

//b=temp;

}



Hereyouhaveacodeblockthathasbeencommentedoutforsomereasonor

other,butinastunningdisplayofsoftwareengineering,theprogrammerwho

originallywrotethecodeactuallyincludedacommenttoindicatewhatwas

goingon.WhentheC++commentformwasusedtocommentouttheblock,the

embeddedcommentwasofnoconcern,buttherecouldhavebeenaserious

problemhadeverybodychosentouseC-stylecomments:

if(a>b){

/*inttemp=a;/*swapaandb*/

a=b;

b=temp;

*/

}



Noticehowtheembeddedcommentinadvertentlyputsaprematureendtothe

commentthatissupposedtocommentoutthecodeblock.

C-stylecommentsstillhavetheirplace.Forexample,they'reinvaluablein

headerfilesthatareprocessedbybothCandC++compilers.Still,ifyoucanuse

C++-stylecomments,youareoftenbetteroffdoingso.

It'sworthpointingoutthatretrogradepreprocessorsthatwerewrittenonlyforC

don'tknowhowtocopewithC++-stylecomments,sothingslikethefollowing

sometimesdon'tworkasexpected:

#defineLIGHT_SPEED3e8//m/sec(inavacuum)



GivenapreprocessorunfamiliarwithC++,thecommentattheendoftheline



becomespartofthemacro!Ofcourse,asisdiscussedinItem1,youshouldn'tbe

usingthepreprocessortodefineconstantsanyway.

BacktoItem3:Prefernewanddeletetomallocandfree.

ContinuetoMemoryManagement



BacktoItem4:PreferC++-stylecomments.

ContinuetoItem5:Usethesameformincorrespondingusesofnewanddelete.



MemoryManagement

MemorymanagementconcernsinC++fallintotwogeneralcamps:gettingit

rightandmakingitperformefficiently.Goodprogrammersunderstandthatthese

concernsshouldbeaddressedinthatorder,becauseaprogramthatisdazzlingly

fastandastoundinglysmallisoflittleuseifitdoesn'tbehavethewayit's

supposedto.Formostprogrammers,gettingthingsrightmeanscallingmemory

allocationanddeallocationroutinescorrectly.Makingthingsperformefficiently,

ontheotherhand,oftenmeanswritingcustomversionsoftheallocationand

deallocationroutines.Gettingthingsrightthereisevenmoreimportant.

Onthecorrectnessfront,C++inheritsfromConeofitsbiggestheadaches,that

ofpotentialmemoryleaks.Evenvirtualmemory,wonderfulinventionthoughit

is,isfinite,andnoteverybodyhasvirtualmemoryinthefirstplace.

InC,amemoryleakariseswhenevermemoryallocatedthroughmallocisnever

returnedthroughfree.ThenamesoftheplayersinC++arenewanddelete,but

thestoryismuchthesame.However,thesituationisimprovedsomewhatbythe

presenceofdestructors,becausetheyprovideaconvenientrepositoryforcallsto

deletethatallobjectsmustmakewhentheyaredestroyed.Atthesametime,

thereismoretoworryabout,becausenewimplicitlycallsconstructorsand

deleteimplicitlycallsdestructors.Furthermore,thereisthecomplicationthat

youcandefineyourownversionsofoperatornewandoperatordelete,both

insideandoutsideofclasses.Thisgivesrisetoallkindsofopportunitiestomake

mistakes.ThefollowingItems(aswellasItemM8)shouldhelpyouavoidsome

ofthemostcommonones.

BacktoItem4:PreferC++-stylecomments.

ContinuetoItem5:Usethesameformincorrespondingusesofnewanddelete.



BacktoMemoryManagement

ContinuetoItem6:Usedeleteonpointermembersindestructors.



Item5:Usethesameformincorrespondingusesofnew

anddelete.

What'swrongwiththispicture?

string*stringArray=newstring[100];

...

deletestringArray;



Everythinghereappearstobeinorder—theuseofnewismatchedwithauseof

delete—butsomethingisstillquitewrong:yourprogram'sbehavioris

undefined.Attheveryleast,99ofthe100stringobjectspointedtoby

stringArrayareunlikelytobeproperlydestroyed,becausetheirdestructorswill

probablyneverbecalled.

Whenyouusenew,twothingshappen.First,memoryisallocated(viathe

functionoperatornew,aboutwhichI'llhavemoretosayinItems7-10aswell

asItemM8).Second,oneormoreconstructorsarecalledforthatmemory.When

youusedelete,twootherthingshappen:oneormoredestructorsarecalledfor

thememory,thenthememoryisdeallocated(viathefunctionoperatordelete

—seeItems8andM8).Thebigquestionfordeleteisthis:howmanyobjects

resideinthememorybeingdeleted?Theanswertothatdetermineshowmany

destructorsmustbecalled.

Actually,thequestionissimpler:doesthepointerbeingdeletedpointtoasingle

objectortoanarrayofobjects?Theonlywayfordeletetoknowisforyouto

tellit.Ifyoudon'tusebracketsinyouruseofdelete,deleteassumesasingle

objectispointedto.Otherwise,itassumesthatanarrayispointedto:

string*stringPtr1=newstring;

string*stringPtr2=newstring[100];

...

deletestringPtr1;//deleteanobject



delete[]stringPtr2;//deleteanarrayof

//objects



Whatwouldhappenifyouusedthe"[]"formonstringPtr1?Theresultis

undefined.Whatwouldhappenifyoudidn'tusethe"[]"formonstringPtr2?

Well,that'sundefinedtoo.Furthermore,it'sundefinedevenforbuilt-intypeslike

ints,eventhoughsuchtypeslackdestructors.Therule,then,issimple:ifyou

use[]whenyoucallnew,youmustuse[]whenyoucalldelete.Ifyoudon't

use[]whenyoucallnew,don'tuse[]whenyoucalldelete.

Thisisaparticularlyimportantruletobearinmindwhenyouarewritingaclass

containingapointerdatamemberandalsoofferingmultipleconstructors,

becausethenyou'vegottobecarefultousethesameformofnewinallthe

constructorstoinitializethepointermember.Ifyoudon't,howwillyouknow

whatformofdeletetouseinyourdestructor?Forafurtherexaminationofthis

issue,seeItem11.

Thisruleisalsoimportantforthetypedef-inclined,becauseitmeansthata

typedef'sauthormustdocumentwhichformofdeleteshouldbeemployed

whennewisusedtoconjureupobjectsofthetypedeftype.Forexample,

considerthistypedef:

typedefstringAddressLines[4];//aperson'saddress

//has4lines,eachof

//whichisastring



BecauseAddressLinesisanarray,thisuseofnew,

string*pal=newAddressLines;//notethat"new

//AddressLines"returns

//astring*,justlike

//"newstring[4]"would



mustbematchedwiththearrayformofdelete:

deletepal;//undefined!

delete[]pal;//fine



Toavoidsuchconfusion,you'reprobablybestoffabstainingfromtypedefsfor

arraytypes.Thatshouldbeeasy,however,becausethestandardC++library(see

Item49)includesstringandvectortemplatesthatreducetheneedforbuilt-in



arraystonearlyzero.Here,forexample,AddressLinescouldbedefinedtobea

vectorofstrings.Thatis,AddressLinescouldbeoftypevector.

BacktoMemoryManagement

ContinuetoItem6:Usedeleteonpointermembersindestructors.



Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Item 2: Prefer <iostream> to <stdio.h>

Tải bản đầy đủ ngay(0 tr)

×