Tải bản đầy đủ - 0 (trang)
Chapter 59.  Don't write namespace usings in a header file or before an #include

Chapter 59.  Don't write namespace usings in a header file or before an #include

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

Summary

Namespaceusingsareforyourconvenience,notforyouto

inflictonothers:Neverwriteausingdeclarationorausing

directivebeforean#includedirective.

Corollary:Inheaderfiles,don'twritenamespace-levelusing

directivesorusingdeclarations;instead,explicitlynamespacequalifyallnames.(Thesecondrulefollowsfromthefirst,

becauseheaderscanneverknowwhatotherheader#includes

mightappearafterthem.)



Discussion

Inshort:Youcanandshouldusenamespaceusingdeclarations

anddirectivesliberallyinyourimplementationfilesafter

#includedirectivesandfeelgoodaboutit.Despiterepeated

assertionstothecontrary,namespaceusingdeclarationsand

directivesarenotevilandtheydonotdefeatthepurposeof

namespaces.Rather,theyarewhatmakenamespacesusable.

Namespacesdeliverthepowerfuladvantageofunambiguous

namemanagement.Mostofthetime,differentprogrammers

don'tchoosetheverysamenameforatypeorfunction;buton

theoffchancethattheydoso,andthatthetwopiecesofcode

endupbeingusedtogether,havingthosenamesinseparate

namespacespreventsthemfromcolliding.(Wedon't,afterall,

wanttheglobalnamespacepollutionexperiencedbydefaultin

languageslikeC.)Intherarecasewhenthereissuchanactual

ambiguity,callingcodecanexplicitlyqualifyanametosay

whichoneitwants.Butthevastmajorityofthetimethereisno

ambiguity:Andthatiswhynamespaceusingdeclarationsand

directivesarewhatmakenamespacesusable,becausethey

greatlyreducecodeclutterbyfreeingyoufromhavingto

tediouslyqualifyeverynameeverytime(whichwouldbe

onerous,andfranklypeoplejustwon'tputupwithit)andstill

lettingyouqualifynamesonlyinthoserarecaseswhenyou

needtoresolveanactualambiguity.

Butusingdeclarationsanddirectivesareforyourcoding

convenience,andyoushouldn'tusetheminawaythataffects

someoneelse'scode.Inparticular,don'twritethemanywhere

theycouldbefollowedbysomeoneelse'scode:Specifically,

don'twritetheminheaderfiles(whicharemeanttobeincluded

inanunboundednumberofimplementationfiles,andyou

shouldn'tmesswiththemeaningofthatothercode)orbefore

an#include(youreallydon'twanttomesswiththemeaning



ofcodeinsomeoneelse'sheader).

Mostpeopleunderstandviscerallywhyausingdirective(e.g.,

usingnamespaceA;)causespollutionwhenitcanaffectcode

thatfollowsandthatisn'tawareofit:Becauseitimportsone

namespacewholesaleintoanother,includingeventhosenames

thathaven'tbeenseenyet,it'sfairlyobviousthatitcaneasily

changethemeaningofcodethatfollows.

Buthere'sthecommontrap:Manypeoplethinkthatusing

declarationsissuedatnamespacelevel(forexample,using

N::Widget;)aresafe.Theyarenot.Theyareatleastas

dangerous,andinasubtlerandmoreinsidiousway.Consider:

//snippet1

namespaceA{

intf(double);

}

//snippet2

namespaceB{

usingA::f;

voidg();

}

//snippet3

namespaceA{

intf(int);

}

//snippet4

voidB::g(){

f(1);//whichoverloadiscalled?

}



Thedangerousthinghappeninghereisthattheusing

declarationtakesasnapshotofwhateverentitiesnamedfin

namespaceAhavebeenseenbythetimetheusingdeclaration

isencountered.So,fromwithinB,whichoverloadsarevisible

dependsonwherethesecodesnippetsexistandinwhatorder

theyarecombined.(Atthispoint,yourinternal"butorder

dependenciesareevil!"klaxonshouldbeblaring.)Thesecond

overload,f(int),wouldbeabettermatchforthecallf(1),

butf(int)willbeinvisibletoB::gifitsdeclarationcomesafter

theusingdeclaration.

Considertwospecificcases.First,let'ssaythatsnippets1,2,

and3areinthreedistinctheaderfiless1.h,s2.h,ands3.h,

andsnippet4inanimplementationfiles4.cppthatincludes

thoseheaderfilestopulltherelevantdeclarations.Then,we

haveanunfortunatephenomenon:ThesemanticsofB::g

dependsontheorderinwhichtheheaderswereincludedin

s4.cpp!Inparticular:

Ifs3.hcomesbefores2.h,B::gwillcallA::f(int).

Elseifs1.hcomesbefores2.h,B::gwillcall

A::f(double).

ElseB::gwon'tcompileatall.

Atleastintheprecedingcase,there'sstillonewell-defined

order,andtheanswerwillbeexactlyoneofthethreelisted

alternatives.

Butnowitgetsmuchworse:Let'sinsteadsaythatsnippets1,

2,3,and4areinfourdistinctheaderfiless1.h,s2.h,s3.h,

ands4.h.Nowlifeisevenmoreunfortunate:Thesemanticsof

B::gdependsontheorderinwhichtheheaderswereincluded,

notonlyins4.hitself,butinanycodethatincludess4.h!In



particular,animplementationfileclient_code.cppmighttryto

includetheheadersinanyorder:

Ifs3.hcomesbefores2.h,B::gwillcallA::f(int).

Elseifs1.hcomesbefores2.h,B::gwillcall

A::f(double).

ElseB::gwon'tcompileatall.

Thisisworsebecausetwoimplementationfilescanincludethe

headersindifferentorders.Considerwhathappensif

client_code_1.cppincludess1.h,s2.h,ands4.hinthat

order,butclient_code_2.cppincludess3.h,s2.h,ands4.h

inthatorder.Then,B::gviolatestheOneDefinitionRule(ODR)

becauseithastwoinconsistentandincompatible

implementationsthatcan'tbothberightonethattriestofall

A::f(int)andonethattriestocallA::f(double).

Sodon'twritenamespaceusingdeclarationsorusing

directivesinaheaderfile,orbeforean#includedirectiveinan

implementationfile.Youareliabletoaffectthemeaningoflater

codebycausingnamespacepollution,bytakinganincomplete

snapshotofthenamesthatyouwanttoimport,orboth.(Note

thequalifier"namespaceusingdeclarationsorusing

directives."Thisdoesn'tapplytowritingclassmemberusing

declarationstobringinbaseclassmembernamesasneeded.)

Inallheaders,andinallimplementationfilesbeforethelast

#include,alwaysexplicitlynamespace-qualifyallnames.In

implementationfilesafterall#includes,youcanandshould

writenamespaceusingdeclarationsanddirectivesliberally.

Thisistherightwaytoreconcilecodebrevitywithmodularity.



Exceptions

Migratingalargeprojectfromanold,pre-ANSI/ISO

implementationofthestandardlibrary(onethatputsallofits

symbolsintheglobalnamespace)toanupdatedone(where

mosteverythingisinnamespacestd)mightforceyouto

carefullyputausingdirectiveinaheaderfile.Thewaytodo

thatisdescribedin[Sutter02].



References

[Stroustrup00]Đ9.2.1[Sutter02]Đ39-40



60.Avoidallocatinganddeallocating

memoryindifferentmodules

Summary

Discussion

References



Summary

Putthingsbackwhereyoufoundthem:Allocatingmemoryin

onemoduleanddeallocatingitinadifferentmodulemakes

yourprogramfragilebycreatingasubtlelong-distance

dependencybetweenthosemodules.Theymustbecompiled

withthesamecompilerversionandsameflags(notablydebug

vs.NDEBUG)andthesamestandardlibraryimplementation,and

inpracticethemoduleallocatingthememoryhadbetterstillbe

loadedwhenthedeallocationhappens.



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

Chapter 59.  Don't write namespace usings in a header file or before an #include

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

×