Tải bản đầy đủ - 0 (trang)
Chapter 6.  Managing Data with Containers

Chapter 6.  Managing Data with Containers

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

Introduction

Thischapterdescribesthedatastructuresinthestandard

librarythatyoucanusetostoredata.Theyaregenerally

referredtoascontainers,sincethey"contain"objectsyouadd

tothem.Thischapteralsodescribesanothersortofcontainer

thatisnotpartofthestandardlibrary,althoughitshipswith

moststandardlibraryimplementations,namelythehashed

container.

Thepartofthelibrarythatcomprisesthecontainersisoften

referredtoastheStandardTemplateLibrary,orSTL,because

thisiswhatitwascalledbeforeitwasincludedintheC++

standard.TheSTLincludesnotonlythecontainersthatarethe

subjectofthischapter,butiteratorsandalgorithms,whichare

thetwootherbuildingblocksoftheSTLthatmakeitaflexible,

genericlibrary.Sincethischapterisprimarilyaboutthe

standardcontainersandnottheSTLinitsentirety,Iwillrefer

tocontainersasthe"standardcontainers"andnot"STL

containers,"asisdoneinmuchoftheC++literature.Although

Idiscussiteratorsandalgorithmsasmuchasnecessaryhere,

botharediscussedinmoredetailinChapter7.

TheC++standardusespreciseterminologytodescribeits

collectionofcontainers.A"container"intheC++standard

libraryisadatastructurethathasawell-definedinterface

describedinthestandard.Forexample,anyC++standard

libraryclassthatcallsitselfacontainermustsupportamember

functionbeginthathasnoparametersandthatreturnsan

iteratorreferringtothefirstelementinthatcontainer.Thereare

anumberofrequiredconstructorsandmemberfunctionsthat

definewhatitistobeacontainerinC++terms.Therearealso

optionalmemberfunctionsonlysomecontainersimplement,

usuallythosethatcanbeimplementedefficiently.

Thesetofallcontainersisfurthersubdividedintotwodifferent



kindsofcontainers:sequencecontainersandassociative

containers.Asequencecontainer(usuallyjustcalleda

sequence)storesobjectsinanorderthatisspecifiedbythe

user,andprovidesarequiredinterface(inadditiontocontainer

requirements)foraccessingandmanipulatingtheelements.

Associativecontainersstoretheirelementsinsortedorder,and

thereforedonotpermityoutoinsertelementsataspecific

location,althoughyoucanprovidehintswhenyouinsertto

improveefficiency.Bothsequencesandassociativecontainers

havearequiredinterfacetheymustsupport,butonly

sequenceshaveanadditionalsetofoperationsthatareonly

supportedbysequencesforwhichtheycanbeimplemented

efficiently.Theseadditionalsequenceoperationsprovidemore

flexibilityandconveniencethantherequiredinterface.

Thissoundsalotlikeinheritance.Asequenceisacontainer,an

associativecontainerisacontainer,butacontainerisnota

sequenceoranassociativecontainer.It'snotinheritance,

though,intheC++sense,butitisinheritanceconceptually.A

vectorisasequence,butitisitsown,standaloneclass;it

doesn'tinheritfromacontainerclassorsomesuchthing

(standardlibraryimplementationsareallowedfreedominhow

theyimplementvectorandothercontainers,butthestandard

doesn'tmandatethatastandardlibraryimplementationinclude

acontainerbaseclass).Agreatdealofthoughtwentintothe

designofthecontainers,andifyouwouldliketoreadmore

aboutitgopickupMattAustern'sGenericProgrammingandthe

STL(AddisonWesley).

Thischapterhastwoparts.Thefirstfewrecipesdescribehow

tousevector,whichisastandardsequence,sinceitisoneof

themorepopulardatastructures.Theydescribehowtousea

vectoreffectivelyandefficiently.Therestoftherecipesdiscuss

mostoftheotherstandardcontainersthatarewidely

applicable,includingthetwononstandardhashedcontainersI

mentionedearlier.







Recipe6.1.UsingvectorsInsteadofArrays

Problem

Youhavetostorethings(built-intypes,objects,pointers,etc.)

inasequence,yourequirerandomaccesstoelements,andyou

can'tbeconfinedtoastaticallysizedarray.



Solution

Usethestandardlibrary'svectorclasstemplate,whichisdefined

in;don'tusearrays.vectorlooksandfeelslikeanarray,

butithasanumberofsafetyandconvenienceadvantagesover

arrays.Example6-1showsafewcommonvectoroperations.



Example6-1.Usingcommonvectormember

functions

#include

#include

#include

usingnamespacestd;

intmain(){

vectorintVec;

vectorstrVec;

//Addelementstothe"back"ofthevectorwithpush_back

intVec.push_back(3);



intVec.push_back(9);

intVec.push_back(6);

strings="Army";

strVec.push_back(s);

s="Navy";

strVec.push_back(s);

s="AirForce";

strVec.push_back(s);



//Youcanaccessthemwithoperator[],justlikeanarray

for(vector::size_typei=0;i
cout<<"intVec["<
}

//Oryoucanuseiterators

for(vector::iteratorp=strVec.begin();

p!=strVec.end();++p){

cout<<*p<<'\n';

}



//Ifyouneedtobesafe,useat()insteadofoperator[].

//willthrowout_of_rangeiftheindexyouuseis>size()

try{

intVec.at(300)=2;

}

catch(out_of_range&e){

cerr<<"out_of_range:"<
}

}



Discussion



Ingeneral,ifyouneedtouseanarray,youshoulduseavector

instead.vectorsoffermoresafetyandflexibilitythanarrays,and

theperformanceoverheadisnegligibleinmostcasesandifyou

findthatit'smorethanyoucantolerate,youcanfine-tune

vectorperformancewithafewmemberfunctions.

Ifyou'renotfamiliarwiththecontainersthatcomewiththe

standardlibrary,ornotacquaintedwithusingclasstemplates

(writingthemisanothermatter),thewayvectorsaredeclared

inExample6-1mayneedsomeexplanation.Thedeclarationfor

avectorlookslikethis:



vector
typenameAllocator=allocator>//Thememoryal

//touse



Thestandardcontainersareparameterizedbythetypeof

objectsyouwantthemtohold.Thereisalsoatemplate

parameterforthememoryallocatortouse,butitdefaultsto

thestandardone,andwritingoneisuncommon,soIdon't

discussithere.

Ifyouwantavectorthatholdsints,declareitasintheexample:

vectorintVec;



Andifyouneedonethatholdsstrings,justchangethevector's

typeargument:

vectorstrVec;



vectorscancontainanyC++typethatsupportscopy



constructionandassignment.

Thenextlogicalthingtodoafteryouinstantiateavectoristo

putsomethinginit.Additemstothebackofitwithpush_back:

intVec.push_back(3);

intVec.push_back(9);

intVec.push_back(6);



Thisisroughlyequivalenttoaddingelements0,1,and2toan

array.Itis"roughly"equivalentbecause,ofcourse,push_backisa

memberfunctionthatreturnsvoidandpushesitsargument

ontothebackofthevector.operator[]returnsthememory

locationreferencedbyanindexinanarray.push_backmakessure

thereisenoughroominthevector'sinternalbuffertoaddits

argument;ifthereis,itaddstheitemtothenextunused

indexifthereisn'troom,itgrowsthebufferusingan

implementation-definedalgorithm,thenaddstheargument

object.

Youcanalsoinsertitemsintothemiddleofavectorwiththe

insertmemberfunction,thoughyoushouldavoiditbecause

doingsorequireslinearcomplexity.SeeRecipe6.2foramore

detaileddiscussionofhowtosidestepperformanceproblems

whenusingvectors.Toinsertanelement,getaniteratortothe

pointwhereyouwantyourinserttobegin(foradiscussionof

iterators,seeRecipe7.1):

strings="Marines";

vector::iteratorp=find(strVec.begin(),

strVec.end(),s);



if(s!=strVec.end())//Insertsimmediatelybeforetheel

strVec.insert(p,s);//ppointsto



Overloadedversionsofinsertallowyoutoinsertncopiesofan

objectintoavector,aswellasinsertanentirerangefrom

anothersequence(thatsequencemaybeanothervector,an

array,alist,andsoon).

Insteadofinserting,youmightwantsimplytoassignthevector

toapreexistingsequencefromsomewhereelse,erasing

whateverwastherebefore.Theassignmemberfunctiondoes

this.Youcanassignanentirerangeofvalues,orncopiesofthe

sameobject,toyourvectorlikethis:

stringsarr[3]={"Ernie","Bert","Elmo"};

strings="Oscar";

strVec.assign(&sarr[0],&sarr[3]);//Assignthissequence

strVec.assign(50,s);//Assign50copiesofs



assignwillresizethevector'sbuffertoaccommodatethenew



sequenceifitislargerthanthepreviousbuffersize.

Onceyouhaveputyourdatainavector,thereareseveralways

forgettingitbackout.Probablythemostintuitiveisoperator[],

whichreturnsareferenceoraconstreferencetotheitemat

thatindex,dependingonwhetherthevectoryouarecallingit

onisconstornot.Inthisrespect,itlooksalotlikeanarray:

for(inti=0;i
std::cout<<"intVec["<
<
}

intVec[2]=32;//lvalue



operator[]alsobehaveslikeanarrayinthatifyouuseanindex



thatishigherthanthelastelementinthevector,theresultsare

undefined,whichusuallymeansyourprogramwillcorruptdata

orcrash.Youcanavoidthisbyqueryingthevectorforthe

numberofelementsitcontainswithsize().Youshouldprefer

iteratorstooperator[]though,becauseusingiteratorsisthe

conventionalwaytoiteratethroughanystandardcontainer:

for(vector::iteratorp=strVec.begin();

p!=strVec.end();++p){

std::cout<<*p<<'\n';

}



Iteratorsarethemorepowerfulapproachbecausetheyallow

formoregenericinteractionwithcontainers.Forexample,ifyou

writeanalgorithmthatoperatesonasequenceofelements

betweentwoiterators,itcanrunagainstanystandard

container.Thisisagenericapproach.Ifyouuserandomaccess

withoperator[],youlimityourselftoonlythosecontainersthat

supportrandomaccess.Theformerapproachiswhatallowsthe

standardlibraryalgorithmsintoworkseamlessly

withthestandardcontainers(andotherthingsthatbehavelike

them).

vectorsalsoprovideyouwithsafetythatyoujustcan'tgetfrom



astandardarray.Unlikearrays,vectorsofferrange-checking

withtheatmemberfunction.Ifyougiveataninvalidindex,it

willthrowanout_of_rangeexception,whichyouthenhavea

chancetocatchandreactaccordingly.Forexample:

try{

intVec.at(300)=2;

}

catch(std::out_of_range&e){

std::cerr<<"out_of_range:"<


}



Asyouknow,ifyoureferenceanelementpasttheendofan

arraywithoperator[],theoperatordoeswhatyouhavetolditto

andfetcheswhateverisatthatmemorylocation.That'snot

goodbecauseeitheryourprogramcrashesfromaccessing

memoryitshouldn't,oritsilentlyupdatesmemorythatbelongs

toanotherheapobject,whichisusuallyworse.operator[]works

thesamewayforvector,butatleastyoucanuseatwhenyou

needtobesafe.

Sothat'sthecrashcourseinvectors.Butwhatisavector?Ifyou

arewritinginC++,youareprobablyperformance-aware,and

don'twanttobegivensomethingandsimplytoldthatitworks.

Fairenough.SeeRecipeRecipe6.2foradiscussionofhow

vectorsworkandtipsforusingthemefficiently.



SeeAlso

Recipe6.2



Recipe6.2.UsingvectorsEfficiently

Problem

Youareusingvectorsandyouhavetightspaceortime

requirementsandneedtoreduceoreliminateoverhead.



Solution

Understandhowavectorisimplemented,knowthecomplexity

ofinsertionanddeletionmemberfunctions,andminimize

unnecessarymemorychurnwiththereservememberfunction.

Example6-2showsafewofthesetechniquesinaction.



Example6-2.Usingavectorefficiently

#include

#include

#include

usingstd::vector;

usingstd::string;

voidf(vector&vec){//Passvecbyreference(or

//pointer,ifyouhaveto)

//...

}

intmain(){



vectorvec(500);//Tellthevectorthatyouplanon



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

Chapter 6.  Managing Data with Containers

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

×