Cum se configurează smartphone-uri și PC-uri. Portal informativ

Utilizare eficientă în 55 de moduri sigure.

Nume: Cele mai bune utilizări pentru C ++ - 35 de noi bune practici pentru îmbunătățirea programelor și proiectelor dvs.

Cartea, care este o continuare a ediției populare a Effective C ++, puteți învăța cum să utilizați cel mai eficient constructele limbajului C ++, precum și să luați în considerare metodele de turnare, implementarea mecanismului RTTI, operatorul regulile de supraîncărcare etc. Cartea oferă recomandări cu privire la utilizarea pointerelor inteligente, constructorilor virtuali, noul operator tamponat, clasele proxy și trimiterea dublă. O atenție deosebită este acordată lucrului cu excepții și posibilităților de utilizare a codului C în programele scrise în C++. Cele mai recente caracteristici ale limbii sunt prezentate în detaliu și prezentate cum să creșteți performanța programelor cu ajutorul lor. Aplicațiile stochează codul șablonului auto_ptr și o listă adnotată de referințe C ++ și resurse de Internet.


Conţinut
Introducere. 14
Capitolul 1. Cele elementare. 23
Regula 1. Distinge între pointeri și legături. 23
Regula 2. Preferați turnările în stil C++. 25
Regula 3. Nu utilizați niciodată polimorfismul pe tablouri. treizeci
Regula 4. Evitați constructorii impliciti inutile. 33
Capitolul 2. Operatori. 38
Regula 5. Atenție la UDF-uri. 38
Regula 6. Distingeți formele de prefix și postfix ale operatorilor de creștere și decreștere. 45
Regula 7. Nu supraîncărcați niciodată operatorii &&, 11 și. 48
Regula 8. Distingeți semnificația operatorilor new și delete. 51
Capitolul 3. Excepții. 57
Regula 9. Pentru a evita scurgerea de resurse, utilizați destructori. 58
Regula 10. Evitați scurgerea de resurse în constructori. 63
Regula 11. Nu propagați gestionarea excepțiilor în afara destructorului. 71
Regula 12. Distingeți aruncarea unei excepții de transmiterea unui parametru sau apelarea unei funcții virtuale. 73
Regula 13. Captură excepții prin referință. 80
Regula 14. Folosiți cu înțelepciune specificațiile de excepție. 84
Regula 15. Estimați costul gestionării excepțiilor. 90
Capitolul 4. Eficienţă. 94
Regula 16. Nu uita de regula 80-20. 95
Regula 17. Folosește calculul leneș. 97
Regula 18. Reduceți costul calculelor așteptate. 106
Regula 19. Investigați cauzele obiectelor temporare. 110
Regula 20. Faceți ușor optimizarea valorii de returnare. 113
Regula 21. Utilizați supraîncărcarea pentru a evita conversia implicită de tip. 116
Regula 22: Ori de câte ori este posibil, utilizați un operator de atribuire în loc de un operator separat. 118
Regula 23. Utilizați biblioteci diferite. 121
Regula 24: Luați în considerare costurile asociate cu funcțiile virtuale, moștenirea multiplă, clasele de bază virtuale și RTTI. 124
Capitolul 5. Recepții. 134
Regula 25. Faceți constructori virtuali și funcții care nu sunt membri ai clasei. 134
Regula 26. Limitează numărul de obiecte din clasă. 140
Regula 27: Solicitați sau respingeți alocarea heap după caz. 154
Regula 28. Folosește indicatori inteligente. 167
Regula 29. Utilizați numărarea referințelor. 190
Regula 30. Utilizați clase proxy. 218
Regula 31. Creați funcții care sunt virtuale în raport cu mai multe obiecte. 231
Capitolul 6. Diverse. 254
Regula 32. Program pentru viitor. 254
Regula 33. Faceți abstracte clasele nonterminale. 259
Regula 34. Să știi să folosești un program apos C și C++. 270
Regula 35. Familiarizați-vă cu standardul lingvistic. 276
Anexa 1. Lista literaturii recomandate. 284
Anexa 2. Implementarea șablonului auto_ptr.

Operatori.
Operatorii supraîncărcați ar trebui tratați cu respect. Ele vă permit să aplicați aceeași sintaxă pentru tipurile definite de utilizator ca și pentru tipurile încorporate și oferă, de asemenea, perspective nemaiauzite datorită funcțiilor din spatele acestor operatori. Dar posibilitatea de a face caractere precum + sau - să facă orice vrei înseamnă, de asemenea, că operatorii supraîncărcați pot face programele complet de neînțeles. Cu toate acestea, există mulți programatori C ++ pricepuți care știu să valorifice puterea operatorilor supraîncărcați fără a transforma un program într-o cutie neagră.

Din păcate, pentru cei mai puțin pricepuți este ușor să greșească. Constructorii cu un singur argument și operatori de conversie de tip implicit pot fi deosebit de deranjanți, deoarece apelurile lor nu se potrivesc întotdeauna textele sursă programe. Acest lucru duce la apariția unor programe al căror comportament este foarte greu de înțeles. O altă problemă apare la supraîncărcarea operatorilor precum && și II, deoarece trecerea de la operatorii încorporați la funcțiile scrise de utilizator are ca rezultat modificări subtile ale semanticii care sunt ușor de trecut cu vederea. În cele din urmă, mulți operatori relaționează între ei conform regulilor standard și, din cauza operatorilor supraîncărcați, relațiile general acceptate sunt uneori încălcate.

În regulile care urmează, am încercat să explic când și cum sunt utilizați operatorii supraîncărcați, cum se comportă, cum ar trebui să se relaționeze între ei și cum pot fi controlați cu toții. Odată ce ai stăpânit materialele din acest capitol, vei supraîncărca (sau nu supraîncărca) operatorii cu aceeași încredere ca un adevărat profesionist.

Descărcare gratuită e-carteîntr-un format convenabil, urmăriți și citiți:
Descărcați cartea Profitați la maximum de C++ - 35 de sfaturi noi pentru a vă îmbunătăți programele și proiectele - Meyers S. - fileskachat.com, descărcare rapidă și gratuită.

Descărcați djvu
Mai jos puteți cumpăra această carte la cel mai bun preț redus cu livrare în toată Rusia.

Scott Meyers

Utilizarea eficientă a C++. 55 de modalități sigure de a îmbunătăți structura și codul programelor dvs

Recenzii ale celei de-a treia edițiiUtilizare eficientă C++

Cartea lui Scott Meyers Utilizarea eficientă a C++, ediția a treia- este concentrarea experienței de programare - experiența care fără ea ți-ar fi primit foarte mult. Această carte este o resursă excelentă pe care o recomand oricui scrie C++ profesional.

Peter Dulimov, ME, Inginer, Unitatea de Evaluare și Cercetare, NAVSYSCOM, Australia

Ediția a treia rămâne cea mai bună carte despre cum să combinați toate piesele din C++ pentru a crea programe eficiente și consistente. Dacă aplicați pentru a fi programator C++, atunci ar trebui să îl citiți.

Eric Nagler, consultant, trainer și autor al Learning C++

Prima ediție a acestei cărți a fost una dintr-un număr mic (foarte mic) de cărți care m-au ajutat să îmi îmbunătățesc semnificativ nivelul de dezvoltator de software profesionist. Ca și alte cărți din această serie, s-a dovedit a fi practică și ușor de citit, dar conținea și multe sfaturi importante. „Utilizare eficientă C++ ", A treia editie, continuă această tradiție. C++ este foarte limbaj puternic programare. Dacă C oferă o frânghie pentru a urca în vârful unui munte, atunci C++ este un întreg magazin în care tot felul de oameni sunt gata să te ajute să faci noduri pe această frânghie. Stăpânirea materialului din această carte vă va crește cu siguranță capacitatea de a utiliza C++ eficient, fără a muri de stres.

Jack W. Reeves, Director executiv Tehnologii software Bleading Edge

Fiecare nou dezvoltator care vine în echipa mea, primește imediat sarcina - să citească această carte.

Michael Lancetta, inginer principal de software

Am citit prima ediție a cărții Effectively Using C++ acum aproximativ 9 ani, iar această carte a devenit imediat una dintre cărțile mele preferate în C++. După părerea mea, cea de-a treia ediție a Efively Using C ++ rămâne o lectură obligatorie pentru oricine dorește să programeze eficient în C ++. Vom trăi într-o lume mai bună dacă programatorii C++ citesc această carte înainte de a scrie prima linie de cod profesional.

Danny Rabbani, inginer software

Prima ediție a lui Scott Meyers Effective Use of C++ a venit la mine când eram un programator obișnuit și încercam din greu să fac cea mai bună treabă pe care o puteam. Și asta a fost mântuirea! Am descoperit că sfaturile lui Meyers sunt practic utile și eficiente, că vor îndeplini 100% ceea ce promite. A treia ediție ajută la utilizarea practică a C ++ atunci când lucrați la proiecte moderne de software serioase, oferind informații despre cele mai recente caracteristici și capabilități ale limbajului. Am descoperit cu plăcere că pot găsi o mulțime de lucruri noi și interesante pentru mine în cea de-a treia ediție a cărții, pe care, după cum mi s-a părut, le cunosc foarte bine.

Michael Topek, manager de program tehnic

Acest ghid autorizat de la Scott Meyers, guru C ++, este destinat oricărei persoane care dorește să folosească C ++ în siguranță și eficient sau care migrează la C ++ din orice alt limbaj orientat pe obiecte. Această carte conține informații valoroase prezentate într-un stil clar, concis, distractiv și perspicace.

Siddhartha Karan Singh, dezvoltator de software

Mulțumiri

Cartea „Utilizarea eficientă a C ++” există de 15 ani și am început să învăț C ++ cu aproximativ 5 ani înainte să o scriu. Astfel, se lucrează la acest proiect de aproximativ 20 de ani. În acest timp, am primit urări, comentarii, corecturi și, uneori, observații copleșitoare de la sute (mii?) de oameni. Fiecare dintre ei a contribuit la dezvoltarea „Utilizării eficiente a C++”. Le sunt recunoscător tuturor.

Am renunțat de mult să mai încerc să-mi amintesc unde și ce am învățat eu, dar nu pot decât să menționez o singură sursă, deoarece o folosesc tot timpul. Acestea sunt grupuri de știri Usenet, în special comp.lang.c ++. Moderat și comp.std.c ++. Multe dintre regulile din această carte (poate cele mai multe) sunt rezultatul gândirii la ideile tehnice discutate în aceste grupuri.

Steve Dewhurst m-a ajutat să selectez material nou pentru cea de-a treia ediție a cărții. Regula 11 preia ideea implementării de copiere și schimb a operatorului = din notele lui Herb Sutter, Problema 13 din cartea sa Exceptional C++ (Addison-Wesley, 2000). Ideea de a prelua o resursă ca inițializare (regula 13) vine din The C++ Programming Language (Addison-Wesley, 2002) de Bjarne Stroustrup. Ideea din spatele regulii 17 este preluată din secțiunea „Cele mai bune practici” a site-ului Boost shared_ptr (http://boost.org/libs/ smart_ptr / shared_ptr.htm # BestPractices) și rafinată pe baza materialului din problema 21 din carte Herb Sutter, „C ++ mai excepțional” (Addison-Wesley, 2002). Regula 29 a fost inspirată de explorarea extensivă de către Herb Sutter a acestui subiect în problemele excepționale C++ 8-19, problemele C++ mai excepționale 17-23 și problemele excepționale C++ 11-13. Stil ”(Addison-Wesley, 2005) . David Abrahams m-a ajutat să înțeleg mai bine cele trei principii de a mă asigura că excepțiile sunt în siguranță. Expresia interfață non-virtuală (NVI) din Regula 35 este preluată din coloana lui Sutter „Virtualitate” din Jurnalul utilizatorilor C/C++ din septembrie 2001. Modelele de design Template Method și Strategy menționate în aceeași regulă sunt preluate din Design Patterns (Addison-Wesley, 1995) de Erich Gamma, Richard Helm, Ralph Johnson (Ralf Johnson și John Vlissides). Ideea pentru limbajul NVI din regula 37 a venit de la Hendrik Schober. Contribuția lui David Smallberg la implementarea setului descrisă la punctul 38. Observația de la punctul 39 că optimizarea unei clase de bază goale este fundamental imposibilă cu moștenirea multiplă este de la David Vandevoorde și Nikolai M. Jossutis (Nickolai M. Josuttis) „Șabloane C ++ " (Addison-Wesley, 2003). Ideea mea inițială despre ce este cuvântul cheie typename în Regula 42 se bazează pe C ++ și C FAQ (http://www.comeaucomputing.com/techtalk/ #typename), care este susținută de Greg Comeau și Leor Zolman m-a ajutat să înțeleg că acest punct de vedere este greșit (vina mea, nu a lui Greg). Tema pentru regula 46 provine din discursul lui Dan Saks „Cum să-ți faci noi prieteni”. Ideea de la sfârșitul Regulii 52 că, dacă declari o versiune de nou, trebuie să le declari pe toate celelalte, este subliniată în problema 22 din Exceptional C++ a lui Herb Sutter. Înțelegerea mea despre procesul de revizuire Boost (rezumat în regula 55) a fost îmbunătățită de David Abrahams.

Scott Meyers

Utilizarea eficientă a C++. 55 de modalități sigure de a îmbunătăți structura și codul programelor dvs

Recenzii ale celei de-a treia edițiiUtilizarea eficientă a C++

Cartea lui Scott Meyers Utilizarea eficientă a C++, ediția a treia- este concentrarea experienței de programare - experiența care fără ea ți-ar fi primit foarte mult. Această carte este o resursă excelentă pe care o recomand oricui scrie C++ profesional.

Peter Dulimov, ME, Inginer, Unitatea de Evaluare și Cercetare, NAVSYSCOM, Australia

Ediția a treia rămâne cea mai bună carte despre cum să combinați toate piesele din C++ pentru a crea programe eficiente și consistente. Dacă aplicați pentru a fi programator C++, atunci ar trebui să îl citiți.

Eric Nagler, consultant, trainer și autor al Learning C++

Prima ediție a acestei cărți a fost una dintr-un număr mic (foarte mic) de cărți care m-au ajutat să îmi îmbunătățesc semnificativ nivelul de dezvoltator de software profesionist. Ca și alte cărți din această serie, s-a dovedit a fi practică și ușor de citit, dar conținea și multe sfaturi importante. „Utilizare eficientă C++ ", A treia editie, continuă această tradiție. C++ este un limbaj de programare foarte puternic. Dacă C oferă o frânghie pentru a urca în vârful unui munte, atunci C++ este un întreg magazin în care tot felul de oameni sunt gata să te ajute să faci noduri pe această frânghie. Stăpânirea materialului din această carte vă va crește cu siguranță capacitatea de a utiliza C++ eficient, fără a muri de stres.

Jack W. Reeves, CEO, Bleading Edge Software Technologies

Fiecărui dezvoltator nou care se alătură echipei mele i se atribuie imediat sarcina de a citi această carte.

Michael Lancetta, inginer principal de software

Am citit prima ediție a cărții Effectively Using C++ acum aproximativ 9 ani, iar această carte a devenit imediat una dintre cărțile mele preferate în C++. După părerea mea, cea de-a treia ediție a Efively Using C ++ rămâne o lectură obligatorie pentru oricine dorește să programeze eficient în C ++. Vom trăi într-o lume mai bună dacă programatorii C++ citesc această carte înainte de a scrie prima linie de cod profesional.

Danny Rabbani, inginer software

Prima ediție a lui Scott Meyers Effective Use of C++ a venit la mine când eram un programator obișnuit și încercam din greu să fac cea mai bună treabă pe care o puteam. Și asta a fost mântuirea! Am descoperit că sfaturile lui Meyers sunt practic utile și eficiente, că vor îndeplini 100% ceea ce promite. A treia ediție ajută la utilizarea practică a C ++ atunci când lucrați la proiecte moderne de software serioase, oferind informații despre cele mai recente caracteristici și capabilități ale limbajului. Am descoperit cu plăcere că pot găsi o mulțime de lucruri noi și interesante pentru mine în cea de-a treia ediție a cărții, pe care, după cum mi s-a părut, le cunosc foarte bine.

Michael Topek, manager de program tehnic

Acest ghid autorizat de la Scott Meyers, guru C ++, este destinat oricărei persoane care dorește să folosească C ++ în siguranță și eficient sau care migrează la C ++ din orice alt limbaj orientat pe obiecte. Această carte conține informații valoroase prezentate într-un stil clar, concis, distractiv și perspicace.

Siddhartha Karan Singh, dezvoltator de software

Mulțumiri

Cartea „Utilizarea eficientă a C ++” există de 15 ani și am început să învăț C ++ cu aproximativ 5 ani înainte să o scriu. Astfel, se lucrează la acest proiect de aproximativ 20 de ani. În acest timp, am primit urări, comentarii, corecturi și, uneori, observații copleșitoare de la sute (mii?) de oameni. Fiecare dintre ei a contribuit la dezvoltarea „Utilizării eficiente a C++”. Le sunt recunoscător tuturor.

Am renunțat de mult să mai încerc să-mi amintesc unde și ce am învățat eu, dar nu pot decât să menționez o singură sursă, deoarece o folosesc tot timpul. Acestea sunt grupuri de știri Usenet, în special comp.lang.c ++. Moderat și comp.std.c ++. Multe dintre regulile din această carte (poate cele mai multe) sunt rezultatul gândirii la ideile tehnice discutate în aceste grupuri.

Steve Dewhurst m-a ajutat să selectez material nou pentru cea de-a treia ediție a cărții. Regula 11 preia ideea implementării de copiere și schimb a operatorului = din notele lui Herb Sutter, Problema 13 din cartea sa Exceptional C++ (Addison-Wesley, 2000). Ideea de a prelua o resursă ca inițializare (regula 13) vine din The C++ Programming Language (Addison-Wesley, 2002) de Bjarne Stroustrup. Ideea din spatele regulii 17 este preluată din secțiunea „Cele mai bune practici” a site-ului Boost shared_ptr (http://boost.org/libs/ smart_ptr / shared_ptr.htm # BestPractices) și rafinată pe baza materialului din problema 21 din carte Herb Sutter, „C ++ mai excepțional” (Addison-Wesley, 2002). Regula 29 a fost inspirată de explorarea extensivă de către Herb Sutter a acestui subiect în problemele excepționale C++ 8-19, problemele C++ mai excepționale 17-23 și problemele excepționale C++ 11-13. Stil ”(Addison-Wesley, 2005) . David Abrahams m-a ajutat să înțeleg mai bine cele trei principii de a mă asigura că excepțiile sunt în siguranță. Expresia interfață non-virtuală (NVI) din Regula 35 este preluată din coloana lui Sutter „Virtualitate” din Jurnalul utilizatorilor C/C++ din septembrie 2001. Modelele de design Template Method și Strategy menționate în aceeași regulă sunt preluate din Design Patterns (Addison-Wesley, 1995) de Erich Gamma, Richard Helm, Ralph Johnson (Ralf Johnson și John Vlissides). Ideea pentru limbajul NVI din regula 37 a venit de la Hendrik Schober. Contribuția lui David Smallberg la implementarea setului descrisă la punctul 38. Observația de la punctul 39 că optimizarea unei clase de bază goale este fundamental imposibilă cu moștenirea multiplă este de la David Vandevoorde și Nikolai M. Jossutis (Nickolai M. Josuttis) „Șabloane C ++ " (Addison-Wesley, 2003). Ideea mea inițială despre ce este cuvântul cheie typename în Regula 42 se bazează pe C ++ și C FAQ (http://www.comeaucomputing.com/techtalk/ #typename), care este susținută de Greg Comeau și Leor Zolman m-a ajutat să înțeleg că acest punct de vedere este greșit (vina mea, nu a lui Greg). Tema pentru regula 46 provine din discursul lui Dan Saks „Cum să-ți faci noi prieteni”. Ideea de la sfârșitul Regulii 52 că, dacă declari o versiune de nou, trebuie să le declari pe toate celelalte, este subliniată în problema 22 din Exceptional C++ a lui Herb Sutter. Înțelegerea mea despre procesul de revizuire Boost (rezumat în regula 55) a fost îmbunătățită de David Abrahams.

Toate cele de mai sus se referă la locul și de la cine am învățat ceva, indiferent de cine a publicat prima dată materialul pe tema relevantă.

Notele mele mai spun că am folosit informații de la Steve Clamage, Antoine Trux, Timothy Knox și Mike Kaelbling, deși din păcate nu este specificat unde And How.

Prima ediție a schițelor revizuite de Tom Cargill, Glenn Caroll, Tony Davis, Brian Kernigan, Jak Kirman, Doug Lea, Moises Lejter), Eugene Santos Jr. (Eugene Santos, Jr), John Shewchuk, John Stasko, Bjarne Stroustrup, Barbara Tilly și Nancy L. Urbano. În plus, sugestii pentru îmbunătățiri care au fost încorporate în reedițiile ulterioare au fost exprimate de Nancy L. Urbano, Chris Treichel, David Corbin, Paul Gibson, Steve Vinoski, Tom Tom Cargill, Neil Rhodes, David Bern, Russ Williams, Robert Brazile, Doug. Morgan, Uwe Steinmuller, Mark Somer (Mark Somer), Doug Moore, David Smallberg, Seith Meltzer, Oleg Steinbuk, David Papurt, Tony Hansen, Peter McCluskey), Stefan Kuhlins, David Braunegg, Paul Chisholm, Adam Zell, Clovis Tondo, Mike Koelbling, Natraj Kini, Lars Numan, Greg Lutz, Tim Johnson, John Lakos, Roger Scott, Scott Frohman, Alan R ooks, Robert Poor, Eric Nagler, Anton Trucks, Cade Roux, Chandrika Gokul, Randy Mangoba și Glenn Teitelbaum.

Schițele ediției a doua revizuite de: Derek Bosch, Tim Johnson, Brian Kernighan, Junichi Kimura, Scott Lewandowski, Laura Michaels, David Smallberg, Clovis Tonado, Chris Van Wyk și Oleg Zabluda. Cursele ulterioare au beneficiat de comentariile lui Daniel Steinberg, Arunprasad Marathe, Doug Stapp, Robert Hall, Cheryl Ferguson, Gary Bartlett, Michael Bartl Tam Michael Tamm, Kendall Beaman, Eric Nagler, Max Hailperin, Joe Gottman, Richard Weeks, Valentin Bonnard, Jun. El, Tim King, Don Mailer, Ted Hill, Marc Harrison, Michael Rubinstein, Marc Rodgers, David Goh, Brenton Brenton Cooper, Andy Thomas-Cramer, Anton Trucks, John Walt, Brian Sharon, Liam Fitzpatric, Bernd Mohr, Harry Yee ( Gary Yee), John O "Hanley, Brady Paterson, Christopher Peterson (Hristos opher Peterson, Feliks Kluzniak, Isi Dunetz, Christopher Creutzi, Ian Cooper, Carl Harris, Marc Stickel, Clay Budin ), Panayotis Matsinopulos, David Smallberg, Herb Sutter, Pajo Misljencevic, Giulio Agostini, Fredrik Blomqvist (Fredrik Blimqvist), Jentoldsender Kuzminski, Kazunobu Kuriyama, Michael Christensen, Jorge Yanez Teruel, Mark Davis, Marty Rabinowitz, Ares Lagae (Ares Lagae) și Alexander Medvedev.

Scott Meyers

Utilizarea eficientă a C++. 55 de modalități sigure de a îmbunătăți structura și codul programelor dvs

Recenzii ale celei de-a treia ediții

Utilizarea eficientă a C++

Cartea lui Scott Meyers Utilizarea eficientă a C++, ediția a treia- este concentrarea experienței de programare - experiența care fără ea ți-ar fi primit foarte mult. Această carte este o resursă excelentă pe care o recomand oricui scrie C++ profesional.

Peter Dulimov, ME, Inginer, Unitatea de Evaluare și Cercetare, NAVSYSCOM, Australia

Ediția a treia rămâne cea mai bună carte despre cum să combinați toate piesele din C++ pentru a crea programe eficiente și consistente. Dacă aplicați pentru a fi programator C++, atunci ar trebui să îl citiți.

Eric Nagler, consultant, trainer și autor al Learning C++

Prima ediție a acestei cărți a fost una dintr-un număr mic (foarte mic) de cărți care m-au ajutat să îmi îmbunătățesc semnificativ nivelul de dezvoltator de software profesionist. Ca și alte cărți din această serie, s-a dovedit a fi practică și ușor de citit, dar conținea și multe sfaturi importante. „Utilizare eficientă C++ ", A treia editie, continuă această tradiție. C++ este un limbaj de programare foarte puternic. Dacă C oferă o frânghie pentru a urca în vârful unui munte, atunci C++ este un întreg magazin în care tot felul de oameni sunt gata să te ajute să faci noduri pe această frânghie. Stăpânirea materialului din această carte vă va crește cu siguranță capacitatea de a utiliza C++ eficient, fără a muri de stres.

Jack W. Reeves, CEO, Bleading Edge Software Technologies

Fiecărui dezvoltator nou care se alătură echipei mele i se atribuie imediat sarcina de a citi această carte.

Michael Lancetta, inginer principal de software

Am citit prima ediție a cărții Effectively Using C++ acum aproximativ 9 ani, iar această carte a devenit imediat una dintre cărțile mele preferate în C++. După părerea mea, cea de-a treia ediție a Efively Using C ++ rămâne o lectură obligatorie pentru oricine dorește să programeze eficient în C ++. Vom trăi într-o lume mai bună dacă programatorii C++ citesc această carte înainte de a scrie prima linie de cod profesional.

Danny Rabbani, inginer software

Prima ediție a lui Scott Meyers Effective Use of C++ a venit la mine când eram un programator obișnuit și încercam din greu să fac cea mai bună treabă pe care o puteam. Și asta a fost mântuirea! Am descoperit că sfaturile lui Meyers sunt practic utile și eficiente, că vor îndeplini 100% ceea ce promite. A treia ediție ajută la utilizarea practică a C ++ atunci când lucrați la proiecte moderne de software serioase, oferind informații despre cele mai recente caracteristici și capabilități ale limbajului. Am descoperit cu plăcere că pot găsi o mulțime de lucruri noi și interesante pentru mine în cea de-a treia ediție a cărții, pe care, după cum mi s-a părut, le cunosc foarte bine.

Michael Topek, manager de program tehnic

Acest ghid autorizat de la Scott Meyers, guru C ++, este destinat oricărei persoane care dorește să folosească C ++ în siguranță și eficient sau care migrează la C ++ din orice alt limbaj orientat pe obiecte. Această carte conține informații valoroase prezentate într-un stil clar, concis, distractiv și perspicace.

Siddhartha Karan Singh, dezvoltator de software

Mulțumiri

Cartea „Utilizarea eficientă a C ++” există de 15 ani și am început să învăț C ++ cu aproximativ 5 ani înainte să o scriu. Astfel, se lucrează la acest proiect de aproximativ 20 de ani. În acest timp, am primit urări, comentarii, corecturi și, uneori, observații copleșitoare de la sute (mii?) de oameni. Fiecare dintre ei a contribuit la dezvoltarea „Utilizării eficiente a C++”. Le sunt recunoscător tuturor.

Am renunțat de mult să mai încerc să-mi amintesc unde și ce am învățat eu, dar nu pot decât să menționez o singură sursă, deoarece o folosesc tot timpul. Acestea sunt grupuri de știri Usenet, în special comp.lang.c ++. Moderat și comp.std.c ++. Multe dintre regulile din această carte (poate cele mai multe) sunt rezultatul gândirii la ideile tehnice discutate în aceste grupuri.

Steve Dewhurst m-a ajutat să selectez material nou pentru cea de-a treia ediție a cărții. Regula 11 preia ideea implementării de copiere și schimb a operatorului = din notele lui Herb Sutter, Problema 13 din cartea sa Exceptional C++ (Addison-Wesley, 2000). Ideea de a prelua o resursă ca inițializare (regula 13) vine din The C++ Programming Language (Addison-Wesley, 2002) de Bjarne Stroustrup. Ideea din spatele regulii 17 este preluată din secțiunea „Cele mai bune practici” a site-ului Boost shared_ptr (http://boost.org/libs/ smart_ptr / shared_ptr.htm # BestPractices) și rafinată pe baza materialului din problema 21 din carte Herb Sutter, „C ++ mai excepțional” (Addison-Wesley, 2002). Regula 29 a fost inspirată de explorarea extensivă de către Herb Sutter a acestui subiect în problemele excepționale C++ 8-19, problemele C++ mai excepționale 17-23 și problemele excepționale C++ 11-13. Stil ”(Addison-Wesley, 2005) . David Abrahams m-a ajutat să înțeleg mai bine cele trei principii de a mă asigura că excepțiile sunt în siguranță. Expresia interfață non-virtuală (NVI) din Regula 35 este preluată din coloana lui Sutter „Virtualitate” din Jurnalul utilizatorilor C/C++ din septembrie 2001. Modelele de design Template Method și Strategy menționate în aceeași regulă sunt preluate din Design Patterns (Addison-Wesley, 1995) de Erich Gamma, Richard Helm, Ralph Johnson (Ralf Johnson și John Vlissides). Ideea pentru limbajul NVI din regula 37 a venit de la Hendrik Schober. Contribuția lui David Smallberg la implementarea setului descrisă la punctul 38. Observația de la punctul 39 că optimizarea unei clase de bază goale este fundamental imposibilă cu moștenirea multiplă este de la David Vandevoorde și Nikolai M. Jossutis (Nickolai M. Josuttis) „Șabloane C ++ " (Addison-Wesley, 2003). Ideea mea inițială despre ce este cuvântul cheie typename în Regula 42 se bazează pe C ++ și C FAQ (http://www.comeaucomputing.com/techtalk/ #typename), care este susținută de Greg Comeau și Leor Zolman m-a ajutat să înțeleg că acest punct de vedere este greșit (vina mea, nu a lui Greg). Tema pentru regula 46 provine din discursul lui Dan Saks „Cum să-ți faci noi prieteni”. Ideea de la sfârșitul Regulii 52 că, dacă declari o versiune de nou, trebuie să le declari pe toate celelalte, este subliniată în problema 22 din Exceptional C++ a lui Herb Sutter. Înțelegerea mea despre procesul de revizuire Boost (rezumat în regula 55) a fost îmbunătățită de David Abrahams.

Toate cele de mai sus se referă la locul și de la cine am învățat ceva, indiferent de cine a publicat prima dată materialul pe tema relevantă.

Notele mele mai spun că am folosit informații de la Steve Clamage, Antoine Trux, Timothy Knox și Mike Kaelbling, deși din păcate nu este specificat unde And How.

Prima ediție a schițelor revizuite de Tom Cargill, Glenn Caroll, Tony Davis, Brian Kernigan, Jak Kirman, Doug Lea, Moises Lejter), Eugene Santos Jr. (Eugene Santos, Jr), John Shewchuk, John Stasko, Bjarne Stroustrup, Barbara Tilly și Nancy L. Urbano. În plus, sugestii pentru îmbunătățiri care au fost încorporate în reedițiile ulterioare au fost exprimate de Nancy L. Urbano, Chris Treichel, David Corbin, Paul Gibson, Steve Vinoski, Tom Tom Cargill, Neil Rhodes, David Bern, Russ Williams, Robert Brazile, Doug. Morgan, Uwe Steinmuller, Mark Somer (Mark Somer), Doug Moore, David Smallberg, Seith Meltzer, Oleg Steinbuk, David Papurt, Tony Hansen, Peter McCluskey), Stefan Kuhlins, David Braunegg, Paul Chisholm, Adam Zell, Clovis Tondo, Mike Koelbling, Natraj Kini, Lars Numan, Greg Lutz, Tim Johnson, John Lakos, Roger Scott, Scott Frohman, Alan R ooks, Robert Poor, Eric Nagler, Anton Trucks, Cade Roux, Chandrika Gokul, Randy Mangoba și Glenn Teitelbaum.

Schițele ediției a doua revizuite de: Derek Bosch, Tim Johnson, Brian Kernighan, Junichi Kimura, Scott Lewandowski, Laura Michaels, David Smallberg, Clovis Tonado, Chris Van Wyk și Oleg Zabluda. Cursele ulterioare au beneficiat de comentariile lui Daniel Steinberg, Arunprasad Marathe, Doug Stapp, Robert Hall, Cheryl Ferguson, Gary Bartlett, Michael Bartl Tam Michael Tamm, Kendall Beaman, Eric Nagler, Max Hailperin, Joe Gottman, Richard Weeks, Valentin Bonnard, Jun. El, Tim King, Don Mailer, Ted Hill, Marc Harrison, Michael Rubinstein, Marc Rodgers, David Goh, Brenton Brenton Cooper, Andy Thomas-Cramer, Anton Trucks, John Walt, Brian Sharon, Liam Fitzpatric, Bernd Mohr, Harry Yee ( Gary Yee), John O "Hanley, Brady Paterson, Christopher Peterson (Hristos opher Peterson, Feliks Kluzniak, Isi Dunetz, Christopher Creutzi, Ian Cooper, Carl Harris, Marc Stickel, Clay Budin ), Panayotis Matsinopulos, David Smallberg, Herb Sutter, Pajo Misljencevic, Giulio Agostini, Fredrik Blomqvist (Fredrik Blimqvist), Jentoldsender Kuzminski, Kazunobu Kuriyama, Michael Christensen, Jorge Yanez Teruel, Mark Davis, Marty Rabinowitz, Ares Lagae (Ares Lagae) și Alexander Medvedev.

Primele versiuni parțiale ale acestei ediții au fost revizuite de: Brian Kernighan, Angelica Lunger, Jesse Lachley, Roger P. Pedersen, Chris Van Wyck, Nicholas Stroustrup și Hendrick Schober. Proiectul complet a fost revizuit de: Leor Zolman, Mike Tsao, Eric Nagler, Zhenet Gutnik, David Abrahams, Gerhard Kreuser, Drosos Kouronis, Brian Kernigan, Andrew Crims, Balog Pal, Emily Jagdhar, Eugene Kalenkovich, Mike Rose, Benjko Carrarara, , Jack Reeves, Steve Shirippa, Martin Fallenstedt, Timothy Knox, Yoon Bai, Michael Lancetta, Philip Janert, Judo Bartholucci, Michael Topic, Jeff Scherpeltz, Chris Naurot, Nishant Mittal, Jeff Sommers, Hrendon Morungoff Lee, Jim Meehan, Alan Geller, Siddhartha Singh, Sam Lee, Sasan Dashinejad, Alex Martin, Steve Cai, Thomas Fruchterman, Corey Hicks, David Smallberg, Gunawardan Kakulapati, Danny Rabbani, Jake Cohen, Hendrik Schuber, Paco Wiziana, Glenn Jeffrey D. Oldham, Nicholas Stroustrup, Matthew Wilson, Andrei Alexandrescu, Tim Johnson, Leon Matthews, Peter Dulimov și Kevlin Henney. Unele paragrafe individuale au fost redactate și de Herb Sutter și Attila F. Feher.

Revizuirea unui manuscris brut (și posibil incomplet) este o muncă dificilă, iar termenele limită strânse nu fac decât să fie și mai dificilă. Sunt recunoscător tuturor celor care și-au exprimat dorința de a mă ajuta în acest sens.

Vizualizarea manuscrisului este cu atât mai dificilă dacă habar nu ai despre material, dar nu trebuie să ratezi nici unul inexactități care s-ar fi putut strecura în text. Este uimitor că există oameni dispuși să editeze texte. Christa Meadowbrook a fost editorul acestei cărți și a reușit să identifice multe greșeli pe care toți ceilalți le-au ratat.

Leor Zolman a verificat toate exemplele de cod de pe diferite compilatoare în timpul revizuirii manuscrisului și apoi a făcut-o din nou după ce am făcut modificările. Dacă rămân greșeli, eu sunt responsabil pentru ele, nu Leor.

Karl Wigers și mai ales Tim Johnson au scris un text de copertă scurt, dar util.

John Waite, editorul primelor două ediții ale acestei cărți, a acceptat din neatenție să lucreze din nou în această calitate. Asistenta lui, Denise Mikelsen, a răspuns invariabil cu un zâmbet plăcut la replicile mele frecvente și enervante (cel puțin așa cred, deși nu am întâlnit-o personal niciodată). Julia Nahil „a scos un pai scurt”, ea trebuia să fie responsabilă de producerea acestei cărți. Timp de șase săptămâni, a stat noaptea pentru a-și ține pasul cu programul, fără să-și piardă calmul. John Fuller (șeful ei) și Marty Rabinovich (șeful ei) au fost, de asemenea, implicați direct în pregătirea publicației. Sarcinile oficiale ale Vanessei Moore au fost să dispună cartea în FrameMaker și să creeze textul PDF, dar ea s-a oferit voluntar să adauge Anexa B și să o formateze pentru tipărire pe coperta interioară. Solveig Hugland a ajutat cu indexul. Sandra Schreueder și Chuti Praserzit s-au ocupat de designul copertei. Chuchi a fost cel care a trebuit să refacă coperta de fiecare dată când am spus: „Ce zici să pun această fotografie, dar cu o dungă de altă culoare?” Chanda Lehry-Cooty era complet epuizată să comercializeze cartea.

Câteva luni în timp ce lucram la manuscris, serialul de televiziune Buffy the Vampire Slayer m-a ajutat să scap de stres la sfârșitul zilei. A fost nevoie de mult efort pentru a alunga discursul lui Buffy din paginile acestei cărți.

Katie Reed m-a învățat să programez în 1971 și mă bucur că rămânem prieteni până astăzi. Donald French ne-a angajat pe Moses Lejter și pe mine pentru a dezvolta tutoriale C++ în 1989 (ceea ce m-a făcut într-adevărînvață C++), iar în 1991 m-a adus să le prezint pe un computer Stratus. Apoi elevii m-au încurajat să scriu ceea ce avea să devină mai târziu prima ediție a acestei cărți. Don mi-a prezentat și lui John White, care a fost de acord să-l publice.

Soția mea, Nancy L. Urbano, continuă să-mi încurajeze scrisul, chiar și după șapte cărți publicate, adaptându-le pentru CD și disertație. Are o răbdare incredibilă. Fără ea, nu aș fi putut niciodată să fac ceea ce am făcut.

De la început până la sfârșit, câinele nostru Persephone a fost însoțitorul meu altruist. Din păcate, ea a participat la majoritatea proiectului în timp ce se afla deja în urna funerară. Ne este foarte dor de ea.

cuvânt înainte

Am scris prima schiță a cărții „Using C ++ Effectively” în 1991. Când a venit vremea celei de-a doua ediții, în 1997, am actualizat semnificativ materialul, dar, nevrând să îi stânjenesc pe cititorii familiarizați cu prima ediție, am încercat pentru a păstra structura existentă: 48 din originalul Cele 50 de reguli au rămas în esență neschimbate. Dacă compari cartea cu o casă, atunci ediția a doua a fost ca redecorarea- tapetare, vopsire in alte culori si inlocuire corpuri de iluminat.

La a treia ediție, m-am hotărât la mult mai mult. (A fost un moment în care mi-am dorit să reconstruiesc totul, pornind de la temelie.) Limbajul C++ s-a schimbat mult din 1991, iar scopul acestei cărți - să identifice tot ceea ce este cel mai important și să-l prezinte sub forma a unei culegeri compacte de recomandări - nu mai îndeplinea setul de reguli formulate cu 15 ani în urmă. În 1991, era rezonabil să presupunem că programatorii cu experiență în lucrul cu C vor trece la C ++. Acum, cu aceeași probabilitate, li se pot atribui cei care au scris anterior în Java sau C #. În 1991, moștenirea și programarea orientată pe obiecte erau noi pentru majoritatea programatorilor. Acum, acestea sunt concepte binecunoscute, iar domeniile pe care oamenii trebuie să le clarifice mai mult sunt excepțiile, modelele și programarea generică. În 1991, nimeni nu auzise de modele de design. Acum, fără să le menționăm, este în general dificil de discutat sisteme software... În 1991, lucrul la un standard formal C++ tocmai începea, acum acest standard are deja 8 ani și se lucrează la următoarea versiune.

Pentru a face față tuturor acestor schimbări, am decis să încep cu fara antecedenteși m-am întrebat: „Ce sfat ar trebui să le dau programatorilor practicanți în C++ în 2005?” Rezultatul este un set de reguli incluse în noua ediție. Această carte include noi capitole despre programarea modelelor și gestionarea resurselor. De fapt, șabloanele rulează ca un fir roșu în tot textul, deoarece puțin în C ++ modern este complet fără ele. Cartea include, de asemenea, materiale despre programare cu excepții, modele de proiectare și noi instrumente de bibliotecă descrise în Raportul tehnic 1 (TR1) (discutat în regula 54). De asemenea, este recunoscut faptul că abordările și tehnicile care funcționează bine pe sistemele cu un singur fir pot să nu fie aplicabile sistemelor cu mai multe fire. Mai mult de jumătate din materialele din această ediție sunt subiecte noi. Cu toate acestea, multe dintre informațiile fundamentale din a doua ediție rămân relevante, așa că am găsit o modalitate de a le repeta într-o formă sau alta (a se vedea Anexa B pentru corespondența dintre regulile ediției a doua și a treia).

Am încercat tot posibilul să fac această carte cât mai utilă, dar, desigur, nu cred că este perfectă. Dacă vi se pare că unele dintre regulile de mai sus nu pot fi considerate aplicabile universal, că există o modalitate mai bună de a rezolva problema formulată sau că discuția unor probleme tehnice nu suficient de clar, incomplet, poate induce în eroare, vă rog să-mi spuneți. Dacă găsiți erori de orice fel - tehnice, gramaticale, tipografice, - orice, - scrieți-mi despre asta. La lansarea următoarei tiraje, voi menționa cu plăcere pe toți cei care îmi atrage atenția asupra unei probleme.

În ciuda faptului că în noua ediție numărul de reguli a crescut la 55, desigur, nu se poate spune că au fost luate în considerare tot felul de întrebări. Dar formularea unui set de reguli care ar trebui urmate în aproape toate aplicațiile este mai dificilă decât ar părea la prima vedere. Dacă aveți sugestii despre ce altceva să includeți, mi-ar plăcea să le iau în considerare.


Stafford, Oregon, aprilie 2005

Introducere

Un lucru este să studiezi fundamentale limbajul și cu totul altul - să înveți să proiectezi și să implementezi programe eficiente. Acest lucru este valabil mai ales pentru C++, cunoscut pentru capacitățile și expresivitatea sa neobișnuit de bogate. Lucrul în C++, atunci când este utilizat corect, poate fi distractiv. O mare varietate de proiecte pot fi exprimate direct și implementate eficient. Un set atent selectat și bine implementat de clase, funcții și șabloane va ajuta să faceți programul simplu, intuitiv, eficient și practic fără erori. Cu abilitățile potrivite, scrierea unor programe eficiente C++ nu este deloc dificilă. Cu toate acestea, dacă este folosit neînțelept, C++ poate produce un cod de neînțeles, greu de întreținut și pur și simplu incorect.

Scopul acestei cărți este să vă arate cum să utilizați C++ eficient. Presupun că sunteți deja familiarizat cu C ++ ca limbaj de programare, și, de asemenea, aveți ceva experiență cu el. Vă aduc la cunoștință instrucțiunile de utilizare a acestui limbaj, urmând ca programele dumneavoastră să fie ușor de înțeles, ușor de întreținut, portabile, extensibile, eficiente și să funcționeze conform așteptărilor.

Sfaturile sugerate pot fi împărțite în două categorii: strategie generală design si uz practic construcții lingvistice separate. O discuție de proiectare este menită să vă ajute să alegeți între diferite abordări pentru rezolvarea unei anumite probleme în C++. Ar trebui să aleg moștenirea sau șabloanele? Moștenire publică sau privată? Moștenire închisă sau compunere? Funcții de membru sau funcții gratuite? Treci prin valoare sau prin referință? Este important să luați decizia corectă de la bun început, deoarece consecințele unei alegeri proaste s-ar putea să nu se manifeste în niciun fel până nu este prea târziu și va fi dificil, consumatoare de timp și costisitoare de refăcut.

Chiar și atunci când știi exact ce vrei să faci, poate fi dificil să obții rezultatele pe care le dorești. Ce tip de valoare ar trebui să returneze operatorul de atribuire? Când ar trebui să fie un destructor virtual? Cum se comportă noul operator dacă nu găsește suficientă memorie? Este extrem de important să lucrați peste aceste detalii, deoarece altfel aproape sigur veți întâlni un comportament neașteptat și chiar inexplicabil al programului. Această carte vă va ajuta să evitați astfel de situații.

Desigur, această carte este greu de numit îndrumare completăîn C++. Mai degrabă, este o colecție de 55 de sfaturi (sau reguli) despre cum să vă îmbunătățiți programele și proiectele. Fiecare paragraf este mai mult sau mai puțin independent de ceilalți, dar majoritatea au referințe încrucișate. Cel mai bun mod de a citi această carte este să începeți cu regula care vă interesează cel mai mult și apoi să urmați linkurile pentru a vedea unde vă conduc.

De asemenea, această carte nu este o introducere în C++. În capitolul 2, de exemplu, discut despre cum să implementez corect constructori, destructori și operatori de atribuire, dar presupun că știți deja ce fac aceste funcții și cum sunt declarate. Există multe cărți C++ pe această temă.

Ţintă acest cărți – evidențiază acele aspecte ale programării C++ care sunt adesea trecute cu vederea. Alte cărți descriu diferite părți ale limbii. De asemenea, explică cum să le combinați între ele pentru a obține programe eficiente. Alte ediții vorbesc despre cum să compilați un program. Și această carte este despre cum să evitați problemele pe care compilatorul nu le poate detecta.

În același timp, această carte se limitează la standard C++. Aici, sunt utilizate numai acele caracteristici lingvistice care sunt descrise în standardul oficial. Portabilitatea este o problemă cheie pentru această carte, așa că dacă sunteți în căutarea unor trucuri specifice platformei, consultați celelalte ediții.

Nu veți găsi în această carte „Evanghelia după C++” – singura cale adevărată către programul ideal C++. Fiecare regulă este o recomandare pentru un aspect sau altul: cum să găsești un design mai bun, cum să eviți greșeli tipice cum să obțineți o eficiență maximă, dar niciunul dintre puncte nu este aplicabil universal. Proiectarea și dezvoltarea software-ului este o sarcină complexă influențată de constrângeri hardware, sistem de operare și aplicații, așa că tot ce pot face este să prezint recomandări pentru a îmbunătăți calitatea programelor.

Dacă urmați sistematic toate recomandările, atunci este puțin probabil să întâlniți cele mai comune capcane care vă așteaptă în C++, dar există excepții de la orice regulă. De aceea sunt oferite explicații în fiecare regulă. Ele constituie partea cea mai importantă a cărții. Numai prin înțelegerea a ceea ce se află în centrul unei anumite reguli puteți decide în ce măsură se potrivește programului dvs. cu limitările sale inerente.

Cel mai bun mod de a folosi această carte este să înțelegeți secretele comportamentului C++, să înțelegeți de ce se comportă așa cum o face și să folosiți comportamentul său în avantajul dvs. Aplicarea oarbă în practică a tuturor regulilor de mai sus este complet nepotrivită, dar, în același timp, nu trebuie să acționați contrar acestor sfaturi fără motive speciale.

Terminologie

Există un mic vocabular C++ pe care fiecare programator ar trebui să-l stăpânească. Următorii termeni sunt suficient de importanți încât să aibă sens să ne asigurăm că îi înțelegem în același mod.

Anunţ(declarația) spune compilatorului numele și tipul ceva, omițând unele detalii. Reclamele arată astfel:


extern int x; // declarație obiect

std :: size_t numDigits (număr int); // declarația funcției

Clasa Widget; // declarație de clasă

template // model declarație

clasa GraphNode; // (vezi regula 42 pentru ce este „nume de tip”.


Rețineți că numesc întregul x „obiect”, chiar dacă este o variabilă încorporată. Unii oameni înțeleg prin „obiecte” doar variabile de tipuri definite de utilizator, dar eu nu sunt unul dintre ele. De asemenea, rețineți că funcția numDigits () returnează tipul std :: size_t, adică tip size_t din spațiul de nume std. Acesta este spațiul de nume în care se află aproape totul din Biblioteca standard C++. Cu toate acestea, deoarece biblioteca standard C (mai precis, C89) poate fi folosită și într-un program C ++, simbolurile moștenite din C (cum ar fi size_t) pot exista în context global, în interiorul std sau ambele, în funcție de fișierele de antet incluse în directiva #include. Pentru această carte, presupun că fișierele antet C++ sunt incluse cu #include. Acesta este motivul pentru care folosesc std :: size_t și nu doar size_t. Când menționez componente standard ale bibliotecii în afara codului, de obicei omit referința std, presupunând că știți că lucruri precum size_t, vector și cout sunt în spațiul de nume std. În programele exemplu, includ întotdeauna std, pentru că altfel codul nu se va compila.

Apropo, size_t este doar un sinonim definit de directiva typedef pentru unele dintre tipurile nesemnate utilizate în C++ pentru tipuri diferite contoare (de exemplu, numărul de caractere din șirurile char *, numărul de elemente din containerele STL etc.). Este, de asemenea, tipul acceptat de funcțiile operatorului în vectori, deques și șiruri. Vom urma această convenție când ne definim propriile funcții de operator în regula 3.

Orice declarație de funcție își specifică semnătură, adică tipurile de parametri și valoarea returnată. Putem spune că semnătura unei funcții este tipul acesteia. Deci, semnătura funcției numDigits este std :: size_t (int), cu alte cuvinte, este „o funcție care ia un int și returnează std :: size_t”. Definiție oficială„Semnăturile” în C++ nu includ tipul de returnare al funcției, dar pentru această carte ne va fi convenabil să presupunem că este încă parte din semnătură.

Definiție(definiție) spune compilatorului detaliile care sunt omise din declarație. Pentru un obiect, o definiție este locul în care compilatorul îi alocă memorie. Pentru o funcție sau un șablon de funcție, definiția conține corpul funcției. O definiție de clasă sau un șablon de clasă își listează membrii:


int x; // definiția obiectului

std :: size_t numDigits (număr int) // definiția funcției

(// (această funcție returnează numărul

std :: size_t digitsSoFar = 1; // zecimale în parametrul său)

în timp ce ((număr / = 10)! = 0) ++ digitsSoFar;

return digitsSoFar;

Class Widget (// definiția clasei

template // definiție șablon

clasa GraphNode (


Inițializare(inițializarea) este procesul de inițializare a unui obiect. Pentru obiectele de tipuri definite de utilizator, inițializarea este efectuată de constructori. Constructor implicit(constructor implicit) este un constructor care poate fi apelat fără argumente. Un astfel de constructor fie nu are deloc parametri, fie are o valoare implicită pentru fiecare parametru:


A (); // constructor implicit

explicit B (int x = 0; bool b = adevărat); // constructor implicit,

// cuvântul cheie „explicit”

explicit C (int x); // acesta nu este un constructor de

// Mod implicit


Constructorii claselor B și C sunt declarați cu cuvântul cheie explicit. Acest lucru împiedică utilizarea lor pentru conversii implicite, deși nu împiedică utilizarea lor dacă conversia este specificată în mod explicit:


void doSomething (B bObject); // funcția preia un obiect de tip B

B bObj1; // obiect de tip B

face Something (bObj1); // ok, B este transmis la doSomething

B bObj (28); // ok, creează B din întregul 28

// (parametrul bool este adevărat în mod implicit)

fă ceva (28); // eroare! face Something acceptă B,

// nu int și nu există niciun implicit

// conversii de la int la B

fă ceva (B (28)); // ok, se folosește constructorul

// B pentru conversie explicită (casting)

// int în B (a se vedea regula 27 pentru informații

// despre tipul de turnare)


Constructorii declarați expliciți sunt, în general, preferați, deoarece împiedică compilatorii să efectueze conversii implicite (adesea nedorite). Dacă nu există un motiv întemeiat pentru utilizarea constructorilor în conversiile implicite, le declar întotdeauna explicite. Vă sfătuiesc să respectați același principiu.

Rețineți că în exemplul precedent, distribuția este evidențiată. Voi continua să folosesc acest accent pentru a sublinia importanța materialului prezentat. (Evidențiez și numerele capitolelor, dar asta doar pentru că mi se pare drăguț.)

Copiere constructor(constructor de copiere) este folosit pentru a inițializa un obiect cu valoarea altui obiect de același tip și operator de atribuire a copierii(operator de atribuire de copiere) este folosit pentru a copia valoarea unui obiect pe altul - de același tip:


Widget (); // constructor implicit

Widget (const Widget & rhs); // constructor de copiere

Widget & operator = (const Widget & rhs); // operator de atribuire de copiere

Widget w1; // apelează constructorul implicit

Widget w2 (w1); // apelează constructorul de copiere

w1 = w2; // apelează operatorul de atribuire

// copie


Fiți atenți când vedeți o construcție asemănătoare unei atribuiri, deoarece sintaxa „=" poate fi folosită și pentru a apela constructorul de copiere:


Widget w3 = w2; // apelați constructorul de copiere!


Din fericire, un constructor de copiere este ușor de distins de o misiune. Dacă este definit un nou obiect (cum ar fi w3 în ultima clauză), atunci constructorul trebuie apelat, nu poate fi o atribuire. Dacă nu este creat niciun obiect nou (ca în „w1 = w2”), atunci constructorul nu este aplicat și aceasta este o atribuire.

Constructorul de copiere este deosebit de important deoarece definește modul în care un obiect este transmis prin valoare. De exemplu, luați în considerare următorul fragment:


bool areAcceptableQuality (Widget w);

dacă (are AcceptableQuality (un Widget))...


Parametrul w este transmis prin valoare funcției hasAcceptableQuality, astfel încât în ​​exemplul de mai sus apelul aWidget este copiat în w. Copierea se face de către constructorul de copiere din clasa Widget. Trecând în general prin valoare mijloace un apel la constructorul de copiere. (Dar, strict vorbind, trecerea tipurilor personalizate după valoare este Idee rea... De obicei, cea mai bună opțiune este să treceți prin referire la o constantă; consultați articolul 20 pentru detalii.)

STL- Biblioteca de șabloane standard este partea bibliotecii standard care se ocupă de containere (de exemplu, vector, listă, set, hartă etc.), iteratoare (adică vector :: iterator, set :: iterator, etc.) etc.), algoritmi (adică for_each, find, sort etc.) și toate funcționalitățile aferente. Este foarte utilizat pe scară largă obiecte funcționale(obiecte funcționale), adică obiecte care se comportă ca niște funcții. Astfel de obiecte sunt reprezentate de clase în care operatorul operator de apel () este supraîncărcat. Dacă nu sunteți familiarizat cu STL, veți avea nevoie, pe lângă această carte, de un manual decent pe această temă, deoarece biblioteca STL este atât de convenabilă încât ar fi de neiertat să nu profitați de beneficiile sale. Trebuie doar să începi să lucrezi cu ea și tu însuți vei simți asta.

Pentru programatorii care au ajuns la C++ din limbaje precum Java sau C #, conceptul de comportament nedefinit. Din diverse motive, comportamentul unor constructe în C++ este într-adevăr nedefinit: nu poți prezice cu certitudine ce se va întâmpla în timpul execuției. Iată două exemple de acest fel:


int * p = 0; // p este un pointer nul

char name = „Daria” // numele este o matrice de lungime 6 (nu uitați de

// final nul!)

char c = nume; // specificând indexul matricei greșit

// generează un comportament nedefinit


Pentru a sublinia că rezultatele comportamentului nedefinit nu pot fi prezise și că pot fi destul de neplăcute, programatorii C++ cu experiență spun adesea că programele cu comportament nedefinit pot șterge conținutul hard disk-ului. Este adevărat: un astfel de program poateșterge-ți HDD, dar s-ar putea să nu. Este mai probabil să se comporte diferit, uneori ok, alteori să se prăbușească și uneori doar să dea rezultate incorecte. Programatorii Wise C++ respectă regula de a evita comportamentul nedefinit. Pe parcursul acestei cărți, vă arăt cum să faceți acest lucru în multe locuri.

Un alt termen care poate deruta programatorii care provin din alte limbi este interfata.În Java și. Limbi compatibile cu NET, interfețele fac parte din limbaj, dar C++ nu are așa ceva, deși Regula 31 se ocupă de o anumită aproximare. Când folosesc termenul „interfață”, de obicei mă refer la semnături de funcții, membrii clasei accesibili („interfață publică”, „interfață protejată”, „ interfață închisă") Sau expresii permise ca parametri de tip pentru șabloane (a se vedea punctul 41). Adică prin interfață mă refer la un concept general de design.

Concept client Este ceva sau cineva care folosește codul pe care îl scrieți (de obicei prin interfețe). Deci, de exemplu, clienții unei funcții sunt utilizatorii acesteia: părțile de cod care apelează funcția (sau îi iau adresa), precum și persoanele care scriu și întrețin un astfel de cod. Clienții unei clase sau șablon sunt părți ale unui program care utilizează acea clasă sau șablon, precum și programatori care scriu sau mențin acele părți. Când vine vorba de clienți, de obicei mă refer la programatori, deoarece aceștia pot fi induși în eroare sau frustrați de interfețele prost proiectate. Codul pe care îl scriu nu are astfel de emoții.

Poate nu obișnuiești să te gândești la clienți, dar voi încerca să te conving de necesitatea de a le face viața cât mai ușoară. La urma urmei, tu însuți ești un client al software-ului dezvoltat de altcineva. La urma urmei, ați dori ca autorii săi să vă ușureze munca? În plus, mai devreme sau mai târziu te vei găsi într-o poziție în care tu însuți devii client al propriului cod (adică vei folosi codul pe care îl scrii), iar atunci vei aprecia că atunci când proiectezi interfețe trebuie să păstrezi interesele clienților în minte.

De-a lungul acestei cărți, mă concentrez adesea pe diferența dintre funcții și șabloanele de funcții și dintre clase și șabloanele de clasă. Acest lucru nu este întâmplător, pentru că ceea ce este adevărat pentru unul este adesea adevărat pentru altul. În situațiile în care nu este cazul, fac o distincție între clase, funcții și șabloane din care sunt derivate clasele și funcțiile.

Convenția de denumire

Am încercat să aleg nume semnificative pentru obiecte, clase, funcții, șabloane etc., dar semantica unora dintre numele cu care am venit poate să nu vă fie clară. De exemplu, folosesc adesea numele lhs și rhs pentru parametri. Aceasta se referă la „partea stângă” și, respectiv, la „partea dreaptă”. Aceste nume sunt utilizate în mod obișnuit în funcțiile care implementează operatori binari, adică operator == și operator *. De exemplu, dacă a și b sunt obiecte care reprezintă numere raționale și dacă obiectele clasei Rational pot fi înmulțite cu operatorul de funcție non-membru * () (un caz similar este descris în regula 24), atunci expresia



este echivalent cu apelarea unei funcții:


operator * (a, b);


În regula 24, declar operatorul * astfel:


const Rational operator * (const Rational & lhs, const Rational & rhs);


După cum puteți vedea, operandul din stânga - a - din interiorul funcției se numește lhs, iar cel din dreapta - b - rhs.

Pentru funcțiile membre, argumentul din partea stângă a instrucțiunii este reprezentat de indicatorul this și singurul parametru rămas pe care îl numesc uneori rhs. Este posibil să fi observat acest lucru în declarațiile unora dintre funcțiile membre Widget din exemplele de mai sus. „Widget” nu înseamnă nimic. Este doar un nume pe care îl folosesc uneori pentru a numi cumva o clasă exemplu. Nu are nimic de-a face cu controalele (widgeturile) folosite în interfețe grafice(GUI).

Adesea numesc pointeri urmând convenția că un pointer către un obiect de tip T se numește pt ("pointer către T"). Aici sunt cateva exemple:


Widget * pw; // pw = pointer către Widget

Avion * pa; // pa = pointer către Avion

clasa GameCharacter;

GameCharacter * pgc; // pgc = pointer către GameCharacter


O convenție similară se aplică link-urilor: rw poate fi o legătură Widget, iar ra poate fi o legătură Avion.

Uneori folosesc numele mf pentru a denumi funcția membru.

Multithreading

În limbajul C++ în sine, nu există nicio idee despre fire și, într-adevăr, despre orice mecanisme de execuție paralelă. Același lucru este valabil și pentru biblioteca standard C++. Cu alte cuvinte, din punctul de vedere al C++, programele multithreaded nu există.

Cu toate acestea, sunt. Deși mă voi concentra în principal pe C++ standard, portabil în această carte, este imposibil să ignor faptul că siguranța firelor este o cerință cu care se confruntă mulți programatori. Recunoscând acest conflict între standardul C++ și realitate, voi observa unde constructele în cauză pot cauza probleme atunci când lucrez într-un mediu cu mai multe fire. Nu credeți că această carte vă va învăța despre programarea C++ multithreading. Deloc. M-am uitat în mare parte la aplicații cu un singur thread, dar nu am ignorat existența multi-threading-ului și am încercat să notez când programatorii care scriu programe multi-threaded ar trebui să-mi urmeze sfaturile cu prudență.

Dacă nu sunteți familiarizat cu conceptul de multithreading și nu sunteți interesat de acest subiect, atunci puteți ignora notele legate de acesta. În caz contrar, rețineți că comentariile mele nu sunt altceva decât un indiciu umil despre ceea ce trebuie să știți dacă veți folosi C ++ pentru a scrie programe multithreaded.

Bibliotecile TR1 și Boost

Veți vedea referințe la bibliotecile TR1 și Boost în această carte. Fiecare dintre ele are o regulă separată (54 - TR1 și 55 - Boost), dar, din păcate, sunt chiar la sfârșitul cărții. Le puteți citi chiar acum dacă doriți, dar dacă preferați să citiți cartea în ordine, mai degrabă decât de la final, atunci următoarele note vă vor ajuta să înțelegeți ce este în joc:

TR1 ("Raportul tehnic 1") este o specificație a unei noi funcționalități adăugate bibliotecă standard C++. Este încadrat cu noi șabloane de clasă și funcții concepute pentru a implementa tabele hash, indicatoare inteligente cu numărare a referințelor, expresii regulate și multe altele. Toate componentele TR1 sunt în spațiul de nume tr1, care este imbricat sub spațiul de nume std.

Boost este o organizație și un site web (http://boost.org) care oferă biblioteci C++ portabile, bine testate, open source. cod sursa... O mare parte din TR1 se bazează pe munca depusă de Boost și până când furnizorii de compilatoare includ TR1 în distribuțiile C++, site-ul Web Boost va rămâne principala sursă de implementări TR1 pentru dezvoltatori. Boost oferă mai mult decât ceea ce este inclus în TR1, dar oricum este bine să știți despre el.

Obișnuiește-te cu C++

Indiferent de experiența de programare, a fi confortabil cu C ++ va dura ceva timp. Este un limbaj puternic cu foarte gamă largă oportunități, dar pentru a le folosi eficient, trebuie să vă schimbați ușor modul de gândire. Cartea este concepută pentru a vă ajuta în acest sens, dar unele întrebări sunt mai importante, altele mai puțin, iar acest capitol este dedicat celor mai importante lucruri.

Regula 1: Tratați C++ ca un conglomerat de limbi

La început, C++ era doar un limbaj C cu unele caracteristici orientate pe obiecte adăugate. Chiar și numele original C ++ ("C cu clase") reflectă această relație.

Pe măsură ce limbajul s-a maturizat, a crescut și s-a dezvoltat, a inclus idei și strategii de programare care au mers dincolo de C cu orele. Excepțiile au necesitat o abordare diferită a structurii funcțiilor (a se vedea regula 29). Șabloanele au schimbat modul în care proiectăm programe (vezi articolul 41), iar STL a introdus o abordare a extensibilității pe care nimeni altcineva nu și-ar fi putut-o imagina.

Astăzi C++ este un limbaj programare cu multiple paradigme, sprijină procedurală, orientată pe obiecte, funcțională, generică și metaprogramare. Această putere și flexibilitate fac din C++ un instrument incomparabil, dar poate fi confuz. Orice recomandare pentru „ aplicare corectă»Există excepții. Cum găsești sens într-o astfel de limbă?

Cel mai bine este să ne gândim la C++ nu ca la un singur limbaj, ci ca la un conglomerat de limbi interconectate. Într-un sublimbaj separat, regulile sunt destul de simple, de înțeles și ușor de reținut. Cu toate acestea, atunci când treceți de la o sublimbă la alta, regulile se pot schimba. Pentru a vedea ideea în C++, trebuie să recunoașteți sublimbajele sale majore. Din fericire, sunt doar patru dintre ele:

C.În profunzimile sale, C ++ se bazează încă pe C. Blocurile, instrucțiunile, preprocesorul, tipurile de date încorporate, matricele, pointerii etc. provin toate din C. În multe cazuri, C ++ oferă mecanisme mai avansate pentru rezolvarea anumitor probleme, decât C (de exemplu, vezi regula 2 - o alternativă la preprocesor și 13 - folosirea obiectelor pentru a gestiona resurse), dar când începeți să lucrați cu partea din C++ care are analogi în C, vă veți da seama că regulile de programare eficientă reflectă natura mai limitată a limbajului C: fără șabloane, fără excepții, fără supraîncărcare etc.

C++ orientat obiect. Această parte a C++ reprezintă ceea ce a fost „C cu clase”, inclusiv constructori și destructori, încapsulare, moștenire, polimorfism, funcții virtuale(legare dinamică) etc. Aceasta este partea din C ++ la care în cel mai se aplică regulile clasice ale proiectării orientate pe obiecte.

C++ cu șabloane. Această parte a C++ se numește programare generică și majoritatea programatorilor știu puține despre ea. Șabloanele pătrund acum C ++ de jos în sus și este un semn al bunei practici de programare să includă constructe de neconceput fără șabloane (de exemplu, vezi regula 46 privind conversiile de tip atunci când apelezi funcții șablon). De fapt, șabloanele, datorită puterii lor, au generat o paradigmă de programare complet nouă: metaprogramarea șablonului(metaprogramare șablon - TMP). Regula 48 oferă o privire de ansamblu asupra TMP, dar dacă nu sunteți un fanatic de șablon, nu aveți niciun motiv să vă gândiți prea mult la asta. TMP nu este una dintre cele mai comune practici de programare C++.

STL. STL este, desigur, o bibliotecă de șabloane, dar foarte specializată. Convențiile pe care le face despre containere, iteratoare, algoritmi și obiecte funcționale funcționează împreună frumos, dar șabloanele și bibliotecile pot fi construite diferit. Când lucrați cu STL, trebuie să respectați convențiile acestuia.

Ține cont de aceste patru sublimbi și nu fi surprins dacă te trezești într-o situație în care eficiența programării necesită să-ți schimbi strategia atunci când treci de la o sublimbaj la alta. De exemplu, pentru tipurile încorporate (stil C) trecerea parametrilor după valoare în caz general este mai eficientă decât trecerea prin referință, dar dacă programați într-un stil orientat pe obiecte, atunci trecerea prin referință la o constantă devine de obicei mai eficientă datorită prezenței constructorilor și destructorilor definiți de utilizator. Acest lucru este valabil mai ales pentru sublimbajul „C ++ cu șabloane”, deoarece acolo de obicei nici nu știi dinainte tipul de obiecte cu care ai de-a face. Dar acum ați trecut la utilizarea STL și din nou vechea regulă C despre trecerea după valoare devine relevantă, deoarece iteratoarele și obiectele funcție sunt modelate prin pointeri C. (Pentru detalii despre alegerea unei metode de transmitere a parametrilor, consultați regula 20.)

Astfel, C++ nu este un limbaj omogen cu un singur set de reguli. Este un conglomerat de sublimbi, fiecare cu convențiile sale. Dacă țineți cont de aceste sublimbi, veți descoperi că C ++ este mult mai ușor de înțeles.

Lucruri de amintit

Regulile pentru programarea eficientă se modifică în funcție de partea din C++ pe care o utilizați.

Regula 2: preferați const, enum și inline decât #define

Ar fi mai bine să numiți această regulă „Compilatorul este de preferat preprocesor”, deoarece #define nu este adesea menționat ca limbaj C ++ deloc. Aceasta e problema. Să ne uităm la un exemplu simplu; incearca sa scrii ceva de genul:


#define ASPECT_RATIO 1.653


Numele simbolic ASPECT_RATIO poate rămâne necunoscut compilatorului sau poate fi eliminat de preprocesor înainte ca codul să fie procesat de compilator. Dacă se întâmplă acest lucru, numele ASPECT_RATIO nu va fi inclus în tabelul cu simboluri. Prin urmare, în timpul compilării, veți primi o eroare (mesajul va menționa valoarea 1.653, nu ASPECT_RATIO). Acest lucru va provoca confuzie. Dacă numele ASPECT_RATIO a fost definit într-un fișier antet pe care nu l-ați scris, atunci nici măcar nu veți ști de unde a venit valoarea 1.653 și veți petrece mult timp căutând un răspuns. Aceeași problemă poate apărea la depanare, deoarece numele pe care îl alegeți nu va fi în tabelul cu simboluri.

Soluția este să înlocuiți macro-ul cu o constantă:


const double AspectRatio = 1,653; // nume scrise cu litere mari,

// folosit de obicei pentru macrocomenzi,

// așa că am decis să o schimbăm


Ca o constantă a limbajului, AspectRatio este vizibil pentru compilator și este plasat în mod natural în tabelul cu simboluri. În plus, utilizarea unei constante în virgulă mobilă (ca în acest exemplu) generează un cod mai compact decât utilizarea #define. Cert este că preprocesorul, substituind orbește valoarea 1.653 în loc de macro-ul ASPECT_RATIO, creează multe copii ale lui 1.653 în codul obiect, în timp ce utilizarea unei constante nu va genera niciodată mai mult de o copie a acestei valori.

Când înlocuiți # definiți constante două lucruri de reținut cazuri speciale... Prima se referă la indicii constante. Deoarece definițiile constante sunt de obicei plasate în fișierele antet (unde sunt accesate de mai multe fișiere sursă), este important ca indicator a fost declarat cu cuvântul cheie const, în plus față de declarația const a ceea ce indică. De exemplu, pentru a declara un șir constant de tip char * în fișierul antet, cuvântul const ar trebui să fie scris de două ori:


const char * const authorName = „Scott Meyers”;


Pentru mai multe informații despre natura și utilizările cuvântului const, în special în legătură cu indicatorii, vezi Regula 3. Dar deja acum merită să reamintim că obiectele de tip șir sunt de obicei preferabile strămoșilor lor - șiruri de tip char *, deci este mai bine să definiți autorName astfel:


const std :: string authorName („Scott Meyers”);


A doua notă se referă la constantele declarate în cadrul clasei. Pentru a limita domeniul de aplicare al unei constante la o clasă, trebuie să o faceți membru al clasei și pentru a vă asigura că există o singură copie a constantei, trebuie să o faceți static membru al:


clasa GamePlayer (

static const int NumTurns = 5; // declarație constantă

scoruri int; // folosind o constantă


Ceea ce vezi mai sus este anunţ NumTurns, nu definiția sa. De obicei, C ++ vă cere să oferiți o definiție pentru tot ceea ce utilizați, dar constantele declarate într-o clasă care sunt statice și de tip încorporat (adică, numere întregi, caractere, boolean) sunt o excepție de la regulă. Atâta timp cât nu încercați să obțineți adresa unei astfel de constante, puteți să o declarați și să o utilizați fără a oferi o definiție. Dacă trebuie să obțineți o adresă sau dacă compilatorul insistă asupra unei definiții, puteți scrie ceva de genul acesta:


const int GamePlayer :: NumTurns; // definiția NumTurns; Vezi mai jos,

// de ce nu este specificată valoarea


Plasați acest cod într-un fișier de implementare, nu într-un fișier antet. Deoarece valoarea inițială a constantei de clasă este reprezentată acolo unde este declarată (adică NumTurns este inițializată la 5 atunci când este declarată), nu este nevoie să specificați o valoare inițială la punctul de definire.

Rețineți, apropo, că nu este posibil să declarați o constantă într-o clasă folosind #define, deoarece #define nu are un scop. Odată definită o macrocomandă, aceasta rămâne în vigoare pentru restul codului compilat (cu excepția cazului în care #undef se găsește undeva mai jos). Aceasta înseamnă că directiva #define este inaplicabilă nu numai pentru declararea constantelor dintr-o clasă, dar, în general, nu poate fi folosită pentru a oferi niciun fel de încapsulare, adică este imposibil să se dea sens expresiei „private #define”. În același timp, datele constante ale membrilor pot fi încapsulate, de exemplu NumTurns.

Este posibil ca compilatoarele mai vechi să nu accepte sintaxa prezentată mai sus, deoarece versiunile anterioare ale limbajului nu aveau permisiunea de a seta valorile membrilor clasei statice în timpul declarației. Mai mult, inițializarea în clasă a fost permisă numai pentru tipurile întregi și pentru constante. Dacă sintaxa de mai sus nu funcționează, atunci valoarea inițială ar trebui specificată în definiție:


clasă Cost Estimate (

static const double FudgeFactor; // declararea unei constante statice

... // clasa - plasat în fișierul antet

const double // definiția unei constante statice

CostEstimate :: FudgeFactor = 1,35; // clasa - plasat în fișierul de implementare


De obicei nu este nevoie de nimic altceva. Singura excepție este aruncată atunci când este necesară o constantă pentru a compila o clasă. De exemplu, atunci când se declară scoruri ale unui tablou GamePlayer ::, compilatorul trebuie să cunoască dimensiunea matricei. Pentru a lucra cu un compilator care interzice din greșeală inițializarea constantelor întregi statice într-o clasă, puteți utiliza o tehnică cunoscută sub numele de truc de enumerare. Se bazează pe faptul că variabilele enumerate pot fi folosite acolo unde sunt așteptate valori int, astfel încât GamePlayer poate fi definit astfel:


clasa GamePlayer (

enumerare (NumTurns = 5); // „truc cu enumerarea” - face din

// NumTurns caracterul cu valoarea 5

scoruri int; // bine


Această tehnică merită cunoscută din mai multe motive. În primul rând, comportamentul trucului de enumerare este, în unele privințe, mai mult ca #define decât constant și, uneori, asta este exact ceea ce doriți. De exemplu, puteți obține adresa unei constante, dar nu puteți obține adresa unei enumerări, la fel cum nu puteți obține adresa #define. Dacă doriți să preveniți obținerea unei adrese sau referințe la o constantă întreagă, atunci folosirea unei enum este o modalitate bună de a impune o astfel de restricție. (Consultați regula 18 pentru mai multe informații despre suportarea constrângerilor de proiectare cu tehnici de codare.) În plus, în timp ce compilatorii buni nu alocă memorie pentru obiecte întregi constante (cu excepția cazului în care creați un pointer sau o referință la obiect), compilatorii mai puțin sofisticați pot face acest lucru și probabil că nu aveți nevoie de el. La fel ca #define, enumerarile nu vor provoca niciodată acest tip de alocare de memorie nedorită.

Al doilea motiv pentru a ști despre trucul de enumerare este pur pragmatic. Este folosit în atât de multe programe, așa că trebuie să puteți recunoaște acest truc atunci când îl întâlniți. În general vorbind, această tehnică este o tehnică fundamentală utilizată în metaprogramarea șablonului (vezi articolul 48).

Să revenim la preprocesor. O altă utilizare greșită comună a directivei #define este crearea de macrocomenzi care arată ca funcții, dar care nu sunt împovărate cu supraîncărcarea apelurilor de funcții. Mai jos este o macrocomandă care apelează o funcție f cu un argument egal cu maximum două valori:


// apelează f, trecând maximul lui a și b

#define CALL_WITH_MAX (a, b) f ((a)> (b)? (a): (b))


Există atât de multe defecte în această linie încât nu este complet clar de unde să începem.

Ori de câte ori scrieți o macrocomandă ca aceasta, trebuie să vă amintiți că toate argumentele trebuie să fie incluse în paranteze. Altfel, riști să te confrunți cu o problemă atunci când cineva o numește cu o expresie drept argument. Dar chiar dacă înțelegi bine, vezi ce lucruri ciudate se pot întâmpla:


int a = 5, b = 0;

CALL_WITH_MAX (++ a, b); // a este incrementat de două ori

CALL_WITH_MAX (++ a, b + 10); // a este incrementat o dată


Ce se întâmplă în interiorul max depinde de ceea ce este comparat!

Din fericire, nu trebuie să suporti comportamente care contravin logicii tale obișnuite. Există o metodă pentru a obține aceeași eficiență ca și utilizarea preprocesorului. Dar oferă atât comportament previzibil, cât și control al tipurilor de argumente (ceea ce este tipic pentru funcțiile obișnuite). Acest lucru se realizează prin utilizarea șablonului de funcție inline (vezi regula 30):


inline void callWithMax (const T & a, const T & b) // Din moment ce nu știm

(// ce este T, atunci trecem

) // a se vedea punctul 20


Acest șablon generează o întreagă familie de funcții, fiecare dintre ele ia două argumente de același tip și apelează f cu cel mai mare dintre ele. Nu este nevoie să puneți paranteze în jurul parametrilor din corpul funcției, nu trebuie să vă faceți griji cu privire la evaluarea parametrilor de mai multe ori și așa mai departe. Mai mult decât atât, deoarece callWithMax este o funcție reală, este supusă regulilor de definire și control al accesului. De exemplu, puteți vorbi despre o funcție încorporată care este un membru privat al unei clase. Este imposibil să descrii așa ceva folosind o macrocomandă.

Prezența const, enum și inline reduce drastic necesitatea unui preprocesor (în special pentru #define), dar nu o elimină complet. Directiva #include rămâne esențială și # ifdef / # ifndef continuă să joace un rol important în controlul compilării. Încă nu este timpul să renunți la preprocesor, dar merită să te gândești cum să scapi de el în viitor.

Lucruri de amintit

Pentru constante simple, directiva #define ar trebui să fie preferată față de obiectele și enumerațiile constante.

În loc de macrocomenzi care imită funcțiile, definite prin #define, este mai bine să folosiți funcții încorporate.

Regula 3: Folosiți const ori de câte ori este posibil

Lucrul tare despre modificatorul const este că impune o anumită constrângere semantică: un anumit obiect nu trebuie modificat, iar compilatorul va impune această constrângere. const vă permite să spuneți compilatorului și programatorilor că o anumită valoare ar trebui să rămână neschimbată. În toate astfel de cazuri, trebuie să precizați acest lucru în mod explicit, apelând compilatorului să vă ajute și asigurându-vă astfel că constrângerea nu este încălcată.


Această sintaxă nu este atât de înfricoșătoare pe cât ar părea. Dacă cuvântul const apare în stânga asteriscului, constanta este ceea ce indică indicatorul; dacă este în dreapta, atunci indicatorul în sine este constant. În cele din urmă, dacă cuvântul const apare pe ambele părți, atunci ambele sunt constante.

Note (editare)

Există o traducere în limba rusă: Stema Sutter. Rezolvarea problemelor complexe în C++. Editura „Williams”, 2002 (Nota editorului).

Există o traducere în limba rusă: Design Patterns. SPb .: Peter (Nota editorului).

Sfârșitul fragmentului de încercare gratuită.

  • Pagini:
    , ,
  • Recenzii ale celei de-a treia ediții
    Utilizarea eficientă a C++

    Cartea lui Scott Meyers Utilizarea eficientă a C++, ediția a treia- este concentrarea experienței de programare - experiența care fără ea ți-ar fi primit foarte mult. Această carte este o resursă excelentă pe care o recomand oricui scrie C++ profesional.

    Peter Dulimov, ME, Inginer, Unitatea de Evaluare și Cercetare, NAVSYSCOM, Australia

    Ediția a treia rămâne cea mai bună carte despre cum să combinați toate piesele din C++ pentru a crea programe eficiente și consistente. Dacă aplicați pentru a fi programator C++, atunci ar trebui să îl citiți.

    Eric Nagler, consultant, trainer și autor al Learning C++

    Prima ediție a acestei cărți a fost una dintr-un număr mic (foarte mic) de cărți care m-au ajutat să îmi îmbunătățesc semnificativ nivelul de dezvoltator de software profesionist. Ca și alte cărți din această serie, s-a dovedit a fi practică și ușor de citit, dar conținea și multe sfaturi importante. „Utilizare eficientă C++ ", A treia editie, continuă această tradiție. C++ este un limbaj de programare foarte puternic. Dacă C oferă o frânghie pentru a urca în vârful unui munte, atunci C++ este un întreg magazin în care tot felul de oameni sunt gata să te ajute să faci noduri pe această frânghie. Stăpânirea materialului din această carte vă va crește cu siguranță capacitatea de a utiliza C++ eficient, fără a muri de stres.

    Jack W. Reeves, CEO, Bleading Edge Software Technologies

    Fiecărui dezvoltator nou care se alătură echipei mele i se atribuie imediat sarcina de a citi această carte.

    Michael Lancetta, inginer principal de software

    Am citit prima ediție a cărții Effectively Using C++ acum aproximativ 9 ani, iar această carte a devenit imediat una dintre cărțile mele preferate în C++. După părerea mea, cea de-a treia ediție a Efively Using C ++ rămâne o lectură obligatorie pentru oricine dorește să programeze eficient în C ++. Vom trăi într-o lume mai bună dacă programatorii C++ citesc această carte înainte de a scrie prima linie de cod profesional.

    Danny Rabbani, inginer software

    Prima ediție a lui Scott Meyers Effective Use of C++ a venit la mine când eram un programator obișnuit și încercam din greu să fac cea mai bună treabă pe care o puteam. Și asta a fost mântuirea! Am descoperit că sfaturile lui Meyers sunt practic utile și eficiente, că vor îndeplini 100% ceea ce promite. A treia ediție ajută la utilizarea practică a C ++ atunci când lucrați la proiecte moderne de software serioase, oferind informații despre cele mai recente caracteristici și capabilități ale limbajului. Am descoperit cu plăcere că pot găsi o mulțime de lucruri noi și interesante pentru mine în cea de-a treia ediție a cărții, pe care, după cum mi s-a părut, le cunosc foarte bine.

    Michael Topek, manager de program tehnic

    Acest ghid autorizat de la Scott Meyers, guru C ++, este destinat oricărei persoane care dorește să folosească C ++ în siguranță și eficient sau care migrează la C ++ din orice alt limbaj orientat pe obiecte. Această carte conține informații valoroase prezentate într-un stil clar, concis, distractiv și perspicace.

    Siddhartha Karan Singh, dezvoltator de software

    Mulțumiri

    Cartea „Utilizarea eficientă a C ++” există de 15 ani și am început să învăț C ++ cu aproximativ 5 ani înainte să o scriu. Astfel, se lucrează la acest proiect de aproximativ 20 de ani. În acest timp, am primit urări, comentarii, corecturi și, uneori, observații copleșitoare de la sute (mii?) de oameni. Fiecare dintre ei a contribuit la dezvoltarea „Utilizării eficiente a C++”. Le sunt recunoscător tuturor.

    Am renunțat de mult să mai încerc să-mi amintesc unde și ce am învățat eu, dar nu pot decât să menționez o singură sursă, deoarece o folosesc tot timpul. Acestea sunt grupuri de știri Usenet, în special comp.lang.c ++. Moderat și comp.std.c ++. Multe dintre regulile din această carte (poate cele mai multe) sunt rezultatul gândirii la ideile tehnice discutate în aceste grupuri.

    Steve Dewhurst m-a ajutat să selectez material nou pentru cea de-a treia ediție a cărții. Regula 11 preia ideea implementării de copiere și schimb a operatorului = din notele lui Herb Sutter, Problema 13 din cartea sa Exceptional C++ (Addison-Wesley, 2000). Ideea de a prelua o resursă ca inițializare (regula 13) vine din The C++ Programming Language (Addison-Wesley, 2002) de Bjarne Stroustrup. Ideea din spatele regulii 17 este preluată din secțiunea „Cele mai bune practici” a site-ului Boost shared_ptr (http://boost.org/libs/ smart_ptr / shared_ptr.htm # BestPractices) și rafinată pe baza materialului din problema 21 din carte Herb Sutter, „C ++ mai excepțional” (Addison-Wesley, 2002). Regula 29 a fost inspirată de explorarea extensivă de către Herb Sutter a acestui subiect în problemele excepționale C++ 8-19, problemele C++ mai excepționale 17-23 și problemele excepționale C++ 11-13. Stil ”(Addison-Wesley, 2005) . David Abrahams m-a ajutat să înțeleg mai bine cele trei principii de a mă asigura că excepțiile sunt în siguranță. Expresia interfață non-virtuală (NVI) din Regula 35 este preluată din coloana lui Sutter „Virtualitate” din Jurnalul utilizatorilor C/C++ din septembrie 2001. Modelele de design Template Method și Strategy menționate în aceeași regulă sunt preluate din Design Patterns (Addison-Wesley, 1995) de Erich Gamma, Richard Helm, Ralph Johnson (Ralf Johnson și John Vlissides). Ideea pentru limbajul NVI din regula 37 a venit de la Hendrik Schober. Contribuția lui David Smallberg la implementarea setului descrisă la punctul 38. Observația de la punctul 39 că optimizarea unei clase de bază goale este fundamental imposibilă cu moștenirea multiplă este de la David Vandevoorde și Nikolai M. Jossutis (Nickolai M. Josuttis) „Șabloane C ++ " (Addison-Wesley, 2003). Înțelegerea mea inițială a cuvântului cheie typename din Regula 42 se bazează pe C ++ și C FAQ ( http://www.comeaucomputing.com/techtalk/#typename), susținut de Greg Comeau, și Leor Zolman m-au ajutat să realizez că acest punct de vedere este greșit (vina mea, nu a lui Greg). Tema pentru regula 46 provine din discursul lui Dan Saks „Cum să-ți faci noi prieteni”. Ideea de la sfârșitul Regulii 52 că, dacă declari o versiune de nou, trebuie să le declari pe toate celelalte, este subliniată în problema 22 din Exceptional C++ a lui Herb Sutter. Înțelegerea mea despre procesul de revizuire Boost (rezumat în regula 55) a fost îmbunătățită de David Abrahams.

    Toate cele de mai sus se referă la locul și de la cine am învățat ceva, indiferent de cine a publicat prima dată materialul pe tema relevantă.

    Notele mele mai spun că am folosit informații de la Steve Clamage, Antoine Trux, Timothy Knox și Mike Kaelbling, deși din păcate nu este specificat unde And How.

    Prima ediție a schițelor revizuite de Tom Cargill, Glenn Caroll, Tony Davis, Brian Kernigan, Jak Kirman, Doug Lea, Moises Lejter), Eugene Santos Jr. (Eugene Santos, Jr), John Shewchuk, John Stasko, Bjarne Stroustrup, Barbara Tilly și Nancy L. Urbano. În plus, sugestii pentru îmbunătățiri care au fost încorporate în reedițiile ulterioare au fost exprimate de Nancy L. Urbano, Chris Treichel, David Corbin, Paul Gibson, Steve Vinoski, Tom Tom Cargill, Neil Rhodes, David Bern, Russ Williams, Robert Brazile, Doug. Morgan, Uwe Steinmuller, Mark Somer (Mark Somer), Doug Moore, David Smallberg, Seith Meltzer, Oleg Steinbuk, David Papurt, Tony Hansen, Peter McCluskey), Stefan Kuhlins, David Braunegg, Paul Chisholm, Adam Zell, Clovis Tondo, Mike Koelbling, Natraj Kini, Lars Numan, Greg Lutz, Tim Johnson, John Lakos, Roger Scott, Scott Frohman, Alan R ooks, Robert Poor, Eric Nagler, Anton Trucks, Cade Roux, Chandrika Gokul, Randy Mangoba și Glenn Teitelbaum.

    Schițele ediției a doua revizuite de: Derek Bosch, Tim Johnson, Brian Kernighan, Junichi Kimura, Scott Lewandowski, Laura Michaels, David Smallberg, Clovis Tonado, Chris Van Wyk și Oleg Zabluda. Cursele ulterioare au beneficiat de comentariile lui Daniel Steinberg, Arunprasad Marathe, Doug Stapp, Robert Hall, Cheryl Ferguson, Gary Bartlett, Michael Bartl Tam Michael Tamm, Kendall Beaman, Eric Nagler, Max Hailperin, Joe Gottman, Richard Weeks, Valentin Bonnard, Jun. El, Tim King, Don Mailer, Ted Hill, Marc Harrison, Michael Rubinstein, Marc Rodgers, David Goh, Brenton Brenton Cooper, Andy Thomas-Cramer, Anton Trucks, John Walt, Brian Sharon, Liam Fitzpatric, Bernd Mohr, Harry Yee ( Gary Yee), John O "Hanley, Brady Paterson, Christopher Peterson (Hristos opher Peterson, Feliks Kluzniak, Isi Dunetz, Christopher Creutzi, Ian Cooper, Carl Harris, Marc Stickel, Clay Budin ), Panayotis Matsinopulos, David Smallberg, Herb Sutter, Pajo Misljencevic, Giulio Agostini, Fredrik Blomqvist (Fredrik Blimqvist), Jentoldsender Kuzminski, Kazunobu Kuriyama, Michael Christensen, Jorge Yanez Teruel, Mark Davis, Marty Rabinowitz, Ares Lagae (Ares Lagae) și Alexander Medvedev.

    Primele versiuni parțiale ale acestei ediții au fost revizuite de: Brian Kernighan, Angelica Lunger, Jesse Lachley, Roger P. Pedersen, Chris Van Wyck, Nicholas Stroustrup și Hendrick Schober. Proiectul complet a fost revizuit de: Leor Zolman, Mike Tsao, Eric Nagler, Zhenet Gutnik, David Abrahams, Gerhard Kreuser, Drosos Kouronis, Brian Kernigan, Andrew Crims, Balog Pal, Emily Jagdhar, Eugene Kalenkovich, Mike Rose, Benjko Carrarara, , Jack Reeves, Steve Shirippa, Martin Fallenstedt, Timothy Knox, Yoon Bai, Michael Lancetta, Philip Janert, Judo Bartholucci, Michael Topic, Jeff Scherpeltz, Chris Naurot, Nishant Mittal, Jeff Sommers, Hrendon Morungoff Lee, Jim Meehan, Alan Geller, Siddhartha Singh, Sam Lee, Sasan Dashinejad, Alex Martin, Steve Cai, Thomas Fruchterman, Corey Hicks, David Smallberg, Gunawardan Kakulapati, Danny Rabbani, Jake Cohen, Hendrik Schuber, Paco Wiziana, Glenn Jeffrey D. Oldham, Nicholas Stroustrup, Matthew Wilson, Andrei Alexandrescu, Tim Johnson, Leon Matthews, Peter Dulimov și Kevlin Henney. Unele paragrafe individuale au fost redactate și de Herb Sutter și Attila F. Feher.

    Revizuirea unui manuscris brut (și posibil incomplet) este o muncă dificilă, iar termenele limită strânse nu fac decât să fie și mai dificilă. Sunt recunoscător tuturor celor care și-au exprimat dorința de a mă ajuta în acest sens.

    Vizualizarea manuscrisului este cu atât mai dificilă dacă habar nu ai despre material, dar nu trebuie să ratezi nici unul inexactități care s-ar fi putut strecura în text. Este uimitor că există oameni dispuși să editeze texte. Christa Meadowbrook a fost editorul acestei cărți și a reușit să identifice multe greșeli pe care toți ceilalți le-au ratat.

    Leor Zolman a verificat toate exemplele de cod de pe diferite compilatoare în timpul revizuirii manuscrisului și apoi a făcut-o din nou după ce am făcut modificările. Dacă rămân greșeli, eu sunt responsabil pentru ele, nu Leor.

    Karl Wigers și mai ales Tim Johnson au scris un text de copertă scurt, dar util.

    John Waite, editorul primelor două ediții ale acestei cărți, a acceptat din neatenție să lucreze din nou în această calitate. Asistenta lui, Denise Mikelsen, a răspuns invariabil cu un zâmbet plăcut la replicile mele frecvente și enervante (cel puțin așa cred, deși nu am întâlnit-o personal niciodată). Julia Nahil „a scos un pai scurt”, ea trebuia să fie responsabilă de producerea acestei cărți. Timp de șase săptămâni, a stat noaptea pentru a-și ține pasul cu programul, fără să-și piardă calmul. John Fuller (șeful ei) și Marty Rabinovich (șeful ei) au fost, de asemenea, implicați direct în pregătirea publicației. Sarcinile oficiale ale Vanessei Moore au fost să dispună cartea în FrameMaker și să creeze textul PDF, dar ea s-a oferit voluntar să adauge Anexa B și să o formateze pentru tipărire pe coperta interioară. Solveig Hugland a ajutat cu indexul. Sandra Schreueder și Chuti Praserzit s-au ocupat de designul copertei. Chuchi a fost cel care a trebuit să refacă coperta de fiecare dată când am spus: „Ce zici să pun această fotografie, dar cu o dungă de altă culoare?” Chanda Lehry-Cooty era complet epuizată să comercializeze cartea.

    Câteva luni în timp ce lucram la manuscris, serialul de televiziune Buffy the Vampire Slayer m-a ajutat să scap de stres la sfârșitul zilei. A fost nevoie de mult efort pentru a alunga discursul lui Buffy din paginile acestei cărți.

    Katie Reed m-a învățat să programez în 1971 și mă bucur că rămânem prieteni până astăzi. Donald French ne-a angajat pe Moses Lejter și pe mine pentru a dezvolta tutoriale C++ în 1989 (ceea ce m-a făcut într-adevărînvață C++), iar în 1991 m-a adus să le prezint pe un computer Stratus. Apoi elevii m-au încurajat să scriu ceea ce avea să devină mai târziu prima ediție a acestei cărți. Don mi-a prezentat și lui John White, care a fost de acord să-l publice.

    Soția mea, Nancy L. Urbano, continuă să-mi încurajeze scrisul, chiar și după șapte cărți publicate, adaptându-le pentru CD și disertație. Are o răbdare incredibilă. Fără ea, nu aș fi putut niciodată să fac ceea ce am făcut.

    De la început până la sfârșit, câinele nostru Persephone a fost însoțitorul meu altruist. Din păcate, ea a participat la majoritatea proiectului în timp ce se afla deja în urna funerară. Ne este foarte dor de ea.

    Top articole similare