Come configurare smartphone e PC. Portale informativo

Uso efficace c 55 modi giusti.

Nome: Ottenere il massimo dal C++ - 35 nuovi suggerimenti per migliorare i tuoi programmi e progetti.

Il libro, che è una continuazione della popolare edizione di Effective C++, permette di apprendere come utilizzare nel modo più efficace i costrutti del linguaggio C++, oltre a considerare come digitare cast, l'implementazione del meccanismo RTTI, l'overloading degli operatori regole, ecc. Il libro fornisce consigli sull'uso di puntatori intelligenti, costruttori virtuali, nuovo operatore bufferizzato, classi proxy e doppio invio. Particolare attenzione è riservata al lavoro con eccezioni e alla possibilità di utilizzare codice C in programmi scritti in C++. Le ultime funzionalità del linguaggio sono descritte in dettaglio e viene presentato come utilizzarle per aumentare le prestazioni dei programmi. Le applicazioni memorizzano il codice per il modello auto_ptr e un elenco annotato di documentazione C++ e risorse Internet.


Contenuto
Introduzione. quattordici
Capitolo 1. Nozioni di base. 23
Regola 1. Distinguere tra puntatori e riferimenti. 23
Regola 2: preferisci il cast del tipo in stile C++. 25
Regola 3. Non usare mai il polimorfismo negli array. trenta
Regola 4: evitare costruttori predefiniti inappropriati. 33
capitolo 2 Operatori. 38
Regola 5: attenzione alle funzioni di conversione del tipo definite dall'utente. 38
Regola 6. Distinguere tra le forme prefisso e suffisso degli operatori di incremento e decremento. 45
Regola 7: non sovraccaricare mai gli operatori &&, 11 e. 48
Regola 8. Distinguere tra il significato degli operatori new e delete. 51
capitolo 3 Eccezioni. 57
Regola 9: usa i distruttori per evitare perdite di risorse. 58
Regola 10 Non disperdere risorse nei costruttori. 63
Regola 11 Non estendere la gestione delle eccezioni al di fuori del distruttore. 71
Regola 12. Distinguere la generazione di un'eccezione dal passaggio di un parametro o dalla chiamata di una funzione virtuale. 73
Punto 13: Cattura le eccezioni passate per riferimento. 80
Regola 14: Usa saggiamente le specifiche delle eccezioni. 84
Regola 15. Stimare il costo della gestione delle eccezioni. 90
capitolo 4 Efficienza. 94
Regola 16 Non dimenticare la regola 80-20. 95
Regola 17: Usa la valutazione pigra. 97
Regola 18: Ridurre il costo dei calcoli previsti. 106
Regola 19. Esaminare le cause degli oggetti temporanei. 110
Punto 20: Semplifica l'ottimizzazione del valore di ritorno. 113
Elemento 21: utilizzare l'overloading per evitare la conversione di tipo implicita. 116
Regola 22. Quando possibile, utilizzare un operatore di assegnazione invece di un singolo operatore. 118
Regola 23. Usa librerie diverse. 121
Punto 24 Considerare i costi associati a funzioni virtuali, eredità multipla, classi base virtuali e RTTI. 124
Capitolo 5 Ricevimenti. 134
Regola 25. Rendi virtual i costruttori e le funzioni che non sono membri della classe. 134
Regola 26: Limita il numero di oggetti in una classe. 140
Punto 27: richiedere o non consentire oggetti nell'heap, a seconda della situazione. 154
Punto 28: Usa i puntatori intelligenti. 167
Regola 29 Utilizzare il conteggio dei riferimenti. 190
Regola 30 Utilizzare classi proxy. 218
Regola 31: Rendi le funzioni virtuali su più di un oggetto. 231
Capitolo 6 Varie. 254
Articolo 32 Programma con uno sguardo al futuro. 254
Regola 33. Rendi astratte le classi non terminali. 259
Regola 34. Saper utilizzare un programma dell'acqua C e C++. 270
Regola 35. Familiarizzare con lo standard linguistico. 276
Allegato 1. Elenco della letteratura raccomandata. 284
Appendice 2. Implementazione del modello auto_ptr.

Operatori.
Gli operatori sovraccarichi devono essere trattati con rispetto. Consentono di utilizzare la stessa sintassi per i tipi definiti dall'utente come per i tipi incorporati e forniscono anche prospettive inaudite grazie alla funzionalità alla base di questi operatori. Ma essere in grado di far fare qualsiasi cosa a caratteri come + o - significa anche che gli operatori sovraccaricati possono creare programmi completamente confusi. Tuttavia, ci sono molti programmatori C++ esperti che sanno come usare la potenza di operatori sovraccarichi senza trasformare il programma in una scatola nera.

Per i meno esperti, purtroppo, è facile sbagliare. I costruttori di argomenti singoli e gli operatori di conversione dei tipi impliciti possono essere particolarmente problematici perché le loro chiamate non sempre corrispondono codice sorgente programmi. Questo porta a programmi il cui comportamento è molto difficile da capire. Un altro problema sorge quando si sovraccaricano operatori come && e II, perché il passaggio dagli operatori incorporati alle funzioni scritte dall'utente comporta modifiche semantiche minori che sono facili da trascurare. Infine, molti operatori sono correlati tra loro secondo regole standard e, a causa di operatori sovraccarichi, le relazioni generalmente accettate vengono talvolta violate.

Nelle seguenti regole ho cercato di spiegare quando e come vengono utilizzati gli operatori sovraccaricati, come si comportano, come dovrebbero relazionarsi tra loro e come tutto questo può essere controllato. Dopo aver imparato il materiale in questo capitolo, sovraccaricare (o non sovraccaricare) gli operatori con la stessa sicurezza di un vero professionista.

Download gratuito e-libro in un formato conveniente, guarda e leggi:
Scarica il libro Sfruttare al massimo il C++ - 35 nuovi suggerimenti per migliorare i tuoi programmi e progetti - Meyers S. - fileskachat.com, download veloce e gratuito.

Scarica djvu
Di seguito puoi acquistare questo libro al miglior prezzo scontato con consegna in tutta la Russia.

Scott Meyers

Uso efficace del C++. 55 Modi sicuri per migliorare la struttura e il codice dei tuoi programmi

Feedback sulla terza edizioneuso efficace C++

libro di scott meyers Usare C++ in modo efficace, terza edizioneè la concentrazione dell'esperienza di programmazione - l'esperienza che senza di essa sarebbe arrivata a un prezzo elevato. Questo libro è un'ottima fonte che consiglio a chiunque scriva C++ in modo professionale.

Peter Dulimov, ME, Ingegnere, Unità di valutazione e ricerca NAVSYSCOM, Australia

La terza edizione rimane il miglior libro su come mettere insieme tutti i pezzi di C++ per creare programmi efficienti e internamente coerenti. Se stai fingendo di essere un programmatore C++, dovresti leggerlo.

Eric Nagler, consulente, docente e autore di Learning C++

La prima edizione di questo libro era uno dei pochi (pochissimi) libri che hanno davvero migliorato il mio livello di sviluppatore di software professionista. Come altri libri di questa serie, era pratico e di facile lettura, ma conteneva anche molti consigli importanti. "Uso efficace C++", terza edizione, continua questa tradizione. C++ è molto linguaggio potente programmazione. Se C ti dà una corda per scalare la cima di una montagna, allora C++ è un negozio pieno di tutti i tipi di persone che sono disposte ad aiutarti a fare nodi su quella corda. Padroneggiare il materiale in questo libro aumenterà sicuramente la tua capacità di usare il C++ in modo efficace e non morirai per lo sforzo.

Jack W. Reeves, Direttore esecutivo Tecnologie software all'avanguardia

Tutti nuovo sviluppatore, che viene nella mia squadra, riceve immediatamente il compito di leggere questo libro.

Michael Lanzetta, Capo Ingegnere Software

Ho letto la prima edizione di Effective C++ circa 9 anni fa ed è diventato rapidamente uno dei miei libri C++ preferiti. A mio parere, Using C++ Effectively 3rd Edition rimane una lettura obbligata per chiunque voglia programmare efficacemente in C++. Vivremo in un mondo migliore se i programmatori C++ leggeranno questo libro prima di scrivere la prima riga di codice professionale.

Danny Rabbani, ingegnere informatico

La prima edizione di The Effective Use of C++ di Scott Meyers mi è venuta in mente quando ero un normale programmatore e mi sono sforzato di fare il miglior lavoro che mi era stato assegnato. Ed è stato un toccasana! Ho scoperto che il consiglio di Meyers è pratico ed efficace, che mantiene al 100% ciò che promette. La terza edizione ti aiuta ad applicare il C++ ai seri progetti software di oggi, fornendo informazioni sugli strumenti e le funzionalità più recenti del linguaggio. Sono stato felice di scoprire che potevo trovare molte cose nuove e interessanti per me stesso nella terza edizione di un libro che pensavo di conoscere molto bene.

Michael Argomento, responsabile del programma tecnico

Questa è un'autorevole guida di Scott Meyers, guru del C++, per chiunque desideri utilizzare il C++ in modo sicuro ed efficiente, o per chi sta effettuando la transizione al C++ da qualsiasi altro linguaggio orientato agli oggetti. Questo libro contiene informazioni preziose presentate in uno stile chiaro, conciso, divertente e perspicace.

Siddhartha Karan Singh, sviluppatore di software

Grazie

L'uso efficace di C++ è in circolazione da 15 anni e ho iniziato a imparare il C++ circa 5 anni prima di scriverlo. Pertanto, il lavoro su questo progetto va avanti da circa 20 anni. Durante questo periodo ho ricevuto desideri, commenti, correzioni e talvolta osservazioni sbalorditive da centinaia (migliaia?) di persone. Ognuno di loro ha contribuito a sviluppare "Usare C++ in modo efficace". Sono grato a tutti loro.

Ho smesso di cercare di ricordare dove e cosa ho imparato molto tempo fa, ma non posso fare a meno di menzionare una fonte perché la uso sempre. Questi sono i newsgroup di Usenet, in particolare comp.lang.c++.moderated e comp.std.c++. Molte delle regole in questo libro (forse la maggior parte) sono nate come risultato del pensiero sulle idee tecniche discusse in questi gruppi.

Steve Dewhurst mi ha aiutato a selezionare nuovo materiale per la terza edizione del libro. Nel punto 11, l'idea di implementare l'operator= mediante copia e scambio è tratta dalle note di Herb Sutter, in particolare dal problema 13 del suo libro Exceptional C++ (Addison-Wesley, 2000). L'idea di acquisire una risorsa come inizializzazione (Regola 13) viene da The C++ Programming Language (Addison-Wesley, 2002) di Bjarne Stroustrup. L'idea alla base della regola 17 è tratta dalla sezione "Best practices" del sito web Boost shared_ptr (http://boost.org/libs/smart_ptr/shared_ptr.htm#BestPractices) e perfezionata sulla base del materiale del problema 21 nel libro Herb Sutter "C++ più eccezionale" (Addison-Wesley, 2002). La regola 29 è stata ispirata dall'ampia esplorazione di Herb Sutter di questo argomento nei problemi 8-19 del C++ eccezionale, nonché dai problemi 17-23 del C++ più eccezionale e dai problemi 11-13 del suo libro C++ eccezionale. Stile" (Addison-Wesley, 2005). David Abrahams mi ha aiutato a comprendere meglio i tre principi per garantire la sicurezza delle eccezioni. Il linguaggio dell'interfaccia non virtuale (NVI) nel punto 35 è tratto dalla colonna "Virtuality" di Herb Sutter nel numero di settembre 2001 del C/C++ Users Journal. I design patterns "Template Method" e "Strategy" citati nella stessa regola sono tratti dal libro "Design Patterns" (Addison-Wesley, 1995) di Erich Gamma, Richard Helm, Ralph Johnson (Ralf Johnson) e John Vlissides (John Vlisside). L'idea di utilizzare l'idioma NVI nella regola 37 è stata suggerita da Hendrik Schober. Il contributo di David Smallberg è l'implementazione dell'insieme descritta nell'articolo 38. L'osservazione fatta nell'articolo 39 che l'ottimizzazione di una classe base vuota è fondamentalmente impossibile con l'ereditarietà multipla è tratta dal libro di David Vandevoorde e Nicholas M. Jossuthis (Nickolai M. Josuttis) "Modelli C++" (Addison-Wesley, 2003). Nel punto 42, la mia idea iniziale di cosa serva la parola chiave typename si basa sulle FAQ C++ e C (http://www.comeaucomputing.com/techtalk/).#typename) gestite da Greg Comeau e Leor Zolman mi ha aiutato a capire che questa visione è sbagliata (colpa mia, non di Greg). Il tema della regola 46 è venuto dal discorso "Come fare nuove amicizie" di Dan Saks. L'idea alla fine della regola 52, che se dichiari una versione di new, devi dichiarare tutte le altre, è esposta nel problema 22 del C++ eccezionale di Herb Sutter. La mia comprensione del processo di revisione Boost (riassunto al punto 55) è stata chiarita da David Abrahams.

Scott Meyers

Uso efficace del C++. 55 Modi sicuri per migliorare la struttura e il codice dei tuoi programmi

Feedback sulla terza edizioneUso efficace del C++

libro di scott meyers Usare C++ in modo efficace, terza edizioneè la concentrazione dell'esperienza di programmazione - l'esperienza che senza di essa sarebbe arrivata a un prezzo elevato. Questo libro è un'ottima fonte che consiglio a chiunque scriva C++ in modo professionale.

Peter Dulimov, ME, Ingegnere, Unità di valutazione e ricerca NAVSYSCOM, Australia

La terza edizione rimane il miglior libro su come mettere insieme tutti i pezzi di C++ per creare programmi efficienti e internamente coerenti. Se stai fingendo di essere un programmatore C++, dovresti leggerlo.

Eric Nagler, consulente, docente e autore di Learning C++

La prima edizione di questo libro era uno dei pochi (pochissimi) libri che hanno davvero migliorato il mio livello di sviluppatore di software professionista. Come altri libri di questa serie, era pratico e di facile lettura, ma conteneva anche molti consigli importanti. "Uso efficace C++", terza edizione, continua questa tradizione. C++ è un linguaggio di programmazione molto potente. Se C ti dà una corda per scalare la cima di una montagna, allora C++ è un negozio pieno di tutti i tipi di persone che sono disposte ad aiutarti a fare nodi su quella corda. Padroneggiare il materiale in questo libro aumenterà sicuramente la tua capacità di usare il C++ in modo efficace e non morirai per lo sforzo.

Jack W. Reeves, CEO di Bleading Edge Software Technologies

Ogni nuovo sviluppatore che entra a far parte del mio team riceve immediatamente il compito di leggere questo libro.

Michael Lanzetta, Capo Ingegnere Software

Ho letto la prima edizione di Effective C++ circa 9 anni fa ed è diventato rapidamente uno dei miei libri C++ preferiti. A mio parere, Using C++ Effectively 3rd Edition rimane una lettura obbligata per chiunque voglia programmare efficacemente in C++. Vivremo in un mondo migliore se i programmatori C++ leggeranno questo libro prima di scrivere la prima riga di codice professionale.

Danny Rabbani, ingegnere informatico

La prima edizione di The Effective Use of C++ di Scott Meyers mi è venuta in mente quando ero un normale programmatore e mi sono sforzato di fare il miglior lavoro che mi era stato assegnato. Ed è stato un toccasana! Ho scoperto che il consiglio di Meyers è pratico ed efficace, che mantiene al 100% ciò che promette. La terza edizione ti aiuta ad applicare il C++ ai seri progetti software di oggi, fornendo informazioni sugli strumenti e le funzionalità più recenti del linguaggio. Sono stato felice di scoprire che potevo trovare molte cose nuove e interessanti per me stesso nella terza edizione di un libro che pensavo di conoscere molto bene.

Michael Argomento, responsabile del programma tecnico

Questa è un'autorevole guida di Scott Meyers, guru del C++, per chiunque desideri utilizzare il C++ in modo sicuro ed efficiente, o per chi sta effettuando la transizione al C++ da qualsiasi altro linguaggio orientato agli oggetti. Questo libro contiene informazioni preziose presentate in uno stile chiaro, conciso, divertente e perspicace.

Siddhartha Karan Singh, sviluppatore di software

Grazie

L'uso efficace di C++ è in circolazione da 15 anni e ho iniziato a imparare il C++ circa 5 anni prima di scriverlo. Pertanto, il lavoro su questo progetto va avanti da circa 20 anni. Durante questo periodo ho ricevuto desideri, commenti, correzioni e talvolta osservazioni sbalorditive da centinaia (migliaia?) di persone. Ognuno di loro ha contribuito a sviluppare "Usare C++ in modo efficace". Sono grato a tutti loro.

Ho smesso di cercare di ricordare dove e cosa ho imparato molto tempo fa, ma non posso fare a meno di menzionare una fonte perché la uso sempre. Questi sono i newsgroup di Usenet, in particolare comp.lang.c++.moderated e comp.std.c++. Molte delle regole in questo libro (forse la maggior parte) sono nate come risultato del pensiero sulle idee tecniche discusse in questi gruppi.

Steve Dewhurst mi ha aiutato a selezionare nuovo materiale per la terza edizione del libro. Nel punto 11, l'idea di implementare l'operator= mediante copia e scambio è tratta dalle note di Herb Sutter, in particolare dal problema 13 del suo libro Exceptional C++ (Addison-Wesley, 2000). L'idea di acquisire una risorsa come inizializzazione (Regola 13) viene da The C++ Programming Language (Addison-Wesley, 2002) di Bjarne Stroustrup. L'idea alla base della regola 17 è tratta dalla sezione "Best practices" del sito web Boost shared_ptr (http://boost.org/libs/smart_ptr/shared_ptr.htm#BestPractices) e perfezionata sulla base del materiale del problema 21 nel libro Herb Sutter "C++ più eccezionale" (Addison-Wesley, 2002). La regola 29 è stata ispirata dall'ampia esplorazione di Herb Sutter di questo argomento nei problemi 8-19 del C++ eccezionale, nonché dai problemi 17-23 del C++ più eccezionale e dai problemi 11-13 del suo libro C++ eccezionale. Stile" (Addison-Wesley, 2005). David Abrahams mi ha aiutato a comprendere meglio i tre principi per garantire la sicurezza delle eccezioni. Il linguaggio dell'interfaccia non virtuale (NVI) nel punto 35 è tratto dalla colonna "Virtuality" di Herb Sutter nel numero di settembre 2001 del C/C++ Users Journal. I design patterns "Template Method" e "Strategy" citati nella stessa regola sono tratti dal libro "Design Patterns" (Addison-Wesley, 1995) di Erich Gamma, Richard Helm, Ralph Johnson (Ralf Johnson) e John Vlissides (John Vlisside). L'idea di utilizzare l'idioma NVI nella regola 37 è stata suggerita da Hendrik Schober. Il contributo di David Smallberg è l'implementazione dell'insieme descritta nell'articolo 38. L'osservazione fatta nell'articolo 39 che l'ottimizzazione di una classe base vuota è fondamentalmente impossibile con l'ereditarietà multipla è tratta dal libro di David Vandevoorde e Nicholas M. Jossuthis (Nickolai M. Josuttis) "Modelli C++" (Addison-Wesley, 2003). Nel punto 42, la mia idea iniziale di cosa serva la parola chiave typename si basa sulle FAQ C++ e C (http://www.comeaucomputing.com/techtalk/).#typename) gestite da Greg Comeau e Leor Zolman mi ha aiutato a capire che questa visione è sbagliata (colpa mia, non di Greg). Il tema della regola 46 è venuto dal discorso "Come fare nuove amicizie" di Dan Saks. L'idea alla fine della regola 52, che se dichiari una versione di new, devi dichiarare tutte le altre, è esposta nel problema 22 del C++ eccezionale di Herb Sutter. La mia comprensione del processo di revisione Boost (riassunto al punto 55) è stata chiarita da David Abrahams.

Tutto quanto sopra riguarda dove e da chi sono stato io a imparare qualcosa, indipendentemente da chi ha pubblicato per primo il materiale sull'argomento in questione.

I miei appunti affermano anche che ho utilizzato informazioni di Steve Clamage, Antoine Trux, Timothy Knox e Mike Kaelbling, anche se sfortunatamente non è specificato dove e come.

Bozze della prima edizione recensite da Tom Cargill, Glenn Carroll, Tony Davis, Brian Kernigan, Jak Kirman, Doug Lea, Moises Lejter), Eugene Santos Jr. (Eugene Santos, Jr), John Shewchuk, John Stasko, Bjarne Stroustrup, Barbara Tilly e Nancy L. Urbano. Inoltre, le richieste di miglioramenti che sono state incluse nelle edizioni successive sono state avanzate da 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 Trax, Cade Roux, Chandrika Gokul, Randy Mangoba e Glenn Teitelbaum.

Bozze della seconda edizione recensite da: Derek Bosch, Tim Johnson, Brian Kernighan, Junichi Kimura, Scott Lewandowski, Laura Michaels, David Smallberg, Clovis Tonado, Chris Van Wyk e Oleg Zabluda. Le edizioni successive hanno beneficiato del commento di Daniel Steinberg, Arunprasad Marathe, Doug Stapp, Robert Hall, Cheryl Ferguson, Gary Bartlett, Michael Tamm (Michael Tamm), Kendall Beaman, Eric Nagler, Max Hailperin, Joe Gottman, Richard Weeks, Valentin Bonnard, Jun Hee, Tim King, Don Mailer, Ted Hill, Marc Harrison, Michael Rubinstein, Marc Rodgers, David Goh, Brenton Cooper, Andy Thomas-Cramer, Anton Thrax, John Walt, Brian Sharon, Liam Fitzpatric, Bernd Mohr, Harry Yee (Gary Yee), John O "Hanley (John O" Hanley), Brady Patreson (Brady Paterson), Christopher Peterson (Christ 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 Blonqvist, Jimmy Snyder, Birial Jensen, Witold Kuzminski, Kazunobu Kuriyama, Michael Christensen, Jorge Yanez Teruel, Mark Davis, Marty Rabinowitz, Ares Lagae e Alexander Medvedev.

Scott Meyers

Uso efficace del C++. 55 Modi sicuri per migliorare la struttura e il codice dei tuoi programmi

Feedback sulla terza edizione

Uso efficace del C++

libro di scott meyers Usare C++ in modo efficace, terza edizioneè la concentrazione dell'esperienza di programmazione - l'esperienza che senza di essa sarebbe arrivata a un prezzo elevato. Questo libro è un'ottima fonte che consiglio a chiunque scriva C++ in modo professionale.

Peter Dulimov, ME, Ingegnere, Unità di valutazione e ricerca NAVSYSCOM, Australia

La terza edizione rimane il miglior libro su come mettere insieme tutti i pezzi di C++ per creare programmi efficienti e internamente coerenti. Se stai fingendo di essere un programmatore C++, dovresti leggerlo.

Eric Nagler, consulente, docente e autore di Learning C++

La prima edizione di questo libro era uno dei pochi (pochissimi) libri che hanno davvero migliorato il mio livello di sviluppatore di software professionista. Come altri libri di questa serie, era pratico e di facile lettura, ma conteneva anche molti consigli importanti. "Uso efficace C++", terza edizione, continua questa tradizione. C++ è un linguaggio di programmazione molto potente. Se C ti dà una corda per scalare la cima di una montagna, allora C++ è un negozio pieno di tutti i tipi di persone che sono disposte ad aiutarti a fare nodi su quella corda. Padroneggiare il materiale in questo libro aumenterà sicuramente la tua capacità di usare il C++ in modo efficace e non morirai per lo sforzo.

Jack W. Reeves, CEO di Bleading Edge Software Technologies

Ogni nuovo sviluppatore che entra a far parte del mio team riceve immediatamente il compito di leggere questo libro.

Michael Lanzetta, Capo Ingegnere Software

Ho letto la prima edizione di Effective C++ circa 9 anni fa ed è diventato rapidamente uno dei miei libri C++ preferiti. A mio parere, Using C++ Effectively 3rd Edition rimane una lettura obbligata per chiunque voglia programmare efficacemente in C++. Vivremo in un mondo migliore se i programmatori C++ leggeranno questo libro prima di scrivere la prima riga di codice professionale.

Danny Rabbani, ingegnere informatico

La prima edizione di The Effective Use of C++ di Scott Meyers mi è venuta in mente quando ero un normale programmatore e mi sono sforzato di fare il miglior lavoro che mi era stato assegnato. Ed è stato un toccasana! Ho scoperto che il consiglio di Meyers è pratico ed efficace, che mantiene al 100% ciò che promette. La terza edizione ti aiuta ad applicare il C++ ai seri progetti software di oggi, fornendo informazioni sugli strumenti e le funzionalità più recenti del linguaggio. Sono stato felice di scoprire che potevo trovare molte cose nuove e interessanti per me stesso nella terza edizione di un libro che pensavo di conoscere molto bene.

Michael Argomento, responsabile del programma tecnico

Questa è un'autorevole guida di Scott Meyers, guru del C++, per chiunque desideri utilizzare il C++ in modo sicuro ed efficiente, o per chi sta effettuando la transizione al C++ da qualsiasi altro linguaggio orientato agli oggetti. Questo libro contiene informazioni preziose presentate in uno stile chiaro, conciso, divertente e perspicace.

Siddhartha Karan Singh, sviluppatore di software

Grazie

L'uso efficace di C++ è in circolazione da 15 anni e ho iniziato a imparare il C++ circa 5 anni prima di scriverlo. Pertanto, il lavoro su questo progetto va avanti da circa 20 anni. Durante questo periodo ho ricevuto desideri, commenti, correzioni e talvolta osservazioni sbalorditive da centinaia (migliaia?) di persone. Ognuno di loro ha contribuito a sviluppare "Usare C++ in modo efficace". Sono grato a tutti loro.

Ho smesso di cercare di ricordare dove e cosa ho imparato molto tempo fa, ma non posso fare a meno di menzionare una fonte perché la uso sempre. Questi sono i newsgroup di Usenet, in particolare comp.lang.c++.moderated e comp.std.c++. Molte delle regole in questo libro (forse la maggior parte) sono nate come risultato del pensiero sulle idee tecniche discusse in questi gruppi.

Steve Dewhurst mi ha aiutato a selezionare nuovo materiale per la terza edizione del libro. Nell'articolo 11, l'idea di implementare l'operatore operator= tramite copia e scambio è tratta dagli appunti di Herb Sutter, in particolare dal Problema 13 del suo libro Exceptional C++ (Addison-Wesley, 2000). L'idea di acquisire una risorsa come inizializzazione (Regola 13) viene da The C++ Programming Language (Addison-Wesley, 2002) di Bjarne Stroustrup. L'idea alla base della regola 17 è tratta dalla sezione "Best practices" del sito web Boost shared_ptr (http://boost.org/libs/smart_ptr/shared_ptr.htm#BestPractices) e perfezionata sulla base del materiale del problema 21 nel libro Herb Sutter "C++ più eccezionale" (Addison-Wesley, 2002). La regola 29 è stata ispirata dall'ampia esplorazione di Herb Sutter di questo argomento nei problemi 8-19 del C++ eccezionale, nonché dai problemi 17-23 del C++ più eccezionale e dai problemi 11-13 del suo libro C++ eccezionale. Stile" (Addison-Wesley, 2005). David Abrahams mi ha aiutato a comprendere meglio i tre principi per garantire la sicurezza delle eccezioni. Il linguaggio dell'interfaccia non virtuale (NVI) nel punto 35 è tratto dalla colonna "Virtuality" di Herb Sutter nel numero di settembre 2001 del C/C++ Users Journal. I design patterns "Template Method" e "Strategy" citati nella stessa regola sono tratti dal libro "Design Patterns" (Addison-Wesley, 1995) di Erich Gamma, Richard Helm, Ralph Johnson (Ralf Johnson) e John Vlissides (John Vlisside). L'idea di utilizzare l'idioma NVI nella regola 37 è stata suggerita da Hendrik Schober. Il contributo di David Smallberg è l'implementazione dell'insieme descritta nell'articolo 38. L'osservazione fatta nell'articolo 39 che l'ottimizzazione di una classe base vuota è fondamentalmente impossibile con l'ereditarietà multipla è tratta dal libro di David Vandevoorde e Nicholas M. Jossuthis (Nickolai M. Josuttis) "Modelli C++" (Addison-Wesley, 2003). Nel punto 42, la mia idea iniziale di cosa serva la parola chiave typename si basa sulle FAQ C++ e C (http://www.comeaucomputing.com/techtalk/).#typename) gestite da Greg Comeau e Leor Zolman mi ha aiutato a capire che questa visione è sbagliata (colpa mia, non di Greg). Il tema della regola 46 è venuto dal discorso "Come fare nuove amicizie" di Dan Saks. L'idea alla fine della regola 52, che se dichiari una versione di new, devi dichiarare tutte le altre, è esposta nel problema 22 del C++ eccezionale di Herb Sutter. La mia comprensione del processo di revisione Boost (riassunto al punto 55) è stata chiarita da David Abrahams.

Tutto quanto sopra riguarda dove e da chi sono stato io a imparare qualcosa, indipendentemente da chi ha pubblicato per primo il materiale sull'argomento in questione.

I miei appunti affermano anche che ho utilizzato informazioni di Steve Clamage, Antoine Trux, Timothy Knox e Mike Kaelbling, anche se sfortunatamente non è specificato dove e come.

Bozze della prima edizione recensite da Tom Cargill, Glenn Carroll, Tony Davis, Brian Kernigan, Jak Kirman, Doug Lea, Moises Lejter), Eugene Santos Jr. (Eugene Santos, Jr), John Shewchuk, John Stasko, Bjarne Stroustrup, Barbara Tilly e Nancy L. Urbano. Inoltre, le richieste di miglioramenti che sono state incluse nelle edizioni successive sono state avanzate da 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 Trax, Cade Roux, Chandrika Gokul, Randy Mangoba e Glenn Teitelbaum.

Bozze della seconda edizione recensite da: Derek Bosch, Tim Johnson, Brian Kernighan, Junichi Kimura, Scott Lewandowski, Laura Michaels, David Smallberg, Clovis Tonado, Chris Van Wyk e Oleg Zabluda. Le edizioni successive hanno beneficiato del commento di Daniel Steinberg, Arunprasad Marathe, Doug Stapp, Robert Hall, Cheryl Ferguson, Gary Bartlett, Michael Tamm (Michael Tamm), Kendall Beaman, Eric Nagler, Max Hailperin, Joe Gottman, Richard Weeks, Valentin Bonnard, Jun Hee, Tim King, Don Mailer, Ted Hill, Marc Harrison, Michael Rubinstein, Marc Rodgers, David Goh, Brenton Cooper, Andy Thomas-Cramer, Anton Thrax, John Walt, Brian Sharon, Liam Fitzpatric, Bernd Mohr, Harry Yee (Gary Yee), John O "Hanley (John O" Hanley), Brady Patreson (Brady Paterson), Christopher Peterson (Christ 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 Blonqvist, Jimmy Snyder, Birial Jensen, Witold Kuzminski, Kazunobu Kuriyama, Michael Christensen, Jorge Yanez Teruel, Mark Davis, Marty Rabinowitz, Ares Lagae e Alexander Medvedev.

Le prime bozze parziali di questa edizione sono state riviste da: Brian Kernighan, Angelique Langer, Jesse Luchley, Roger P. Pedersen, Chris Van Wyck, Nicholas Stroustrup e Hendrik Schober. Recensione della bozza completa recensita da: Leor Zolman, Mike Tsao, Eric Nagler, Gene Gutnick, David Abrahams, Gerhard Kreuser, Drosos Kouronis, Brian Kernighan, Andrew Krims, Balogh Pal, Emily Jagdhar, Evgeny Kalenkovic, Mike Rose, Enrico Carrara, Benjamin Burke , Jack Reeves, Steve Schirippa, Martin Fallenstedt, Timothy Knox, Yun Bai, Michael Lanzetta, Philip Janert, Judo Bartolucci, Michael Topic, Jeff Sherpeltz, Chris Nauroth, Nishant Mittal, Jeff Sommers, Hal Moroff, Vincent Manis, Brendon Chang, Greg Lee, Jim Meehan, Alan Geller, Siddhartha Singh, Sam Lee, Sasan Dashtinejad, Alex Martin, Steve Kai, Thomas Fruchterman, Corey Hicks, David Smallberg, Gunawardan Kakulapati, Danny Rabbani, Jake Cohen, Hendrik Schuber, Paco Viziana, Glenn Kennedy Jeffrey D. Oldham, Nicholas Stroustrup, Matthew Wilson, Andrei Alexandrescu, Tim Johnson, Leon Matthews, Peter Dulimov e Kevlin Henney. Le bozze di alcuni singoli paragrafi sono state riviste anche da Herb Sutter e Attila F. Feher.

Revisionare un manoscritto grezzo (e forse incompleto) è un lavoro duro e le scadenze strette lo rendono solo più difficile. Ringrazio tutti coloro che hanno espresso il desiderio di aiutarmi in questo.

Revisionare un manoscritto è tanto più difficile se non hai idea del materiale, ma non dovresti perderlo nessuno imprecisioni che potrebbero insinuarsi nel testo. È sorprendente che ci siano persone che accettano di modificare i testi. Christa Meadowbrook è stata l'editore di questo libro ed è stata in grado di individuare alcuni errori che tutti gli altri hanno mancato.

Leor Zolman ha esaminato il manoscritto per tutti i campioni di codice su diversi compilatori, quindi l'ha fatto di nuovo dopo aver apportato le modifiche. Se permangono errori, ne sono responsabile, non Lheor.

Carl Vigers e soprattutto Tim Johnson hanno scritto un breve ma utile testo per la copertina.

John Waite, editore delle prime due edizioni di questo libro, acconsentì imprudentemente a lavorare di nuovo in tale veste. La sua assistente, Denise Michelsen, rispondeva invariabilmente con un sorriso piacevole alle mie frequenti e fastidiose osservazioni (almeno credo, anche se non l'ho mai incontrata personalmente). Julia Nakhil "ha tirato la cannuccia", doveva essere incaricata della produzione di questo libro. Per sei settimane si è alzata la notte per stare al passo con i suoi impegni senza perdere la calma. Anche John Fuller (il suo capo) e Marty Rabinowitz (il suo capo) sono stati coinvolti direttamente nel processo di produzione. I compiti ufficiali di Vanessa Moore erano di incorniciare il libro in FrameMaker e creare il testo PDF, ma ha contribuito volontariamente all'Appendice B e lo ha formattato per la stampa sulla copertina interna. Solveig Huegland ha aiutato con l'indice. Sandra Schroeder e Chuti Prasercit erano responsabili del design della copertina. Era Chuti che doveva rifare la copertina ogni volta che dicevo: "Che ne dici di mettere questa foto, ma con una striscia di un colore diverso?". Chanda Leri-Couty è completamente esausta per la commercializzazione del libro.

Durante i mesi in cui ho lavorato al manoscritto, la serie televisiva Buffy l'ammazzavampiri mi ha aiutato a rilassarmi alla fine della giornata. Ci sono voluti molti sforzi per bandire i discorsi di Buffy dalle pagine di questo libro.

Kathy Reed mi ha insegnato a programmare nel 1971 e sono felice che rimaniamo amici fino ad oggi. Donald French ha assunto me e Moses Legter per sviluppare tutorial C++ nel 1989 (il che mi ha reso veramente imparare C++), e nel 1991 mi ha invitato a presentarli sul computer Stratus. Poi gli studenti mi hanno incoraggiato a scrivere quella che poi è diventata la prima edizione di questo libro. Don mi ha anche presentato John White, che ha accettato di pubblicarlo.

Mia moglie, Nancy L. Urbano, continua a incoraggiare la mia scrittura, anche dopo aver pubblicato sette libri, adattamenti su CD e una dissertazione. Ha una pazienza incredibile. Senza di lei, non sarei mai stato in grado di fare quello che ho fatto.

Dall'inizio alla fine, il nostro cane Persefone è stato il mio compagno disinteressato. Sfortunatamente, ha partecipato alla maggior parte del progetto mentre era già nell'urna funeraria. Ci manca molto.

Prefazione

Ho scritto la prima bozza di Effective C++ nel 1991. Quando è arrivata l'ora della seconda edizione nel 1997, ho sostanzialmente aggiornato il materiale, ma non volendo confondere i lettori che hanno familiarità con la prima edizione, ho cercato di mantenere la struttura esistente: 48 di l'originale Le 50 regole sono rimaste sostanzialmente invariate. Rispetto a un libro e a una casa, la seconda edizione era come ridecorando– reincollaggio della carta da parati, verniciatura in altri colori e sostituzione dei corpi illuminanti.

Nella terza edizione mi sono avventurato in molto di più. (C'è stato un tempo in cui volevo ricostruire tutto da zero.) Il linguaggio C++ è cambiato molto dal 1991 e gli obiettivi di questo libro: far emergere le cose più importanti e presentarle in una raccolta compatta di consigli —non rientra più nell'insieme di regole formulate 15 anni fa. Nel 1991 era ragionevole presumere che i programmatori con esperienza in C stessero passando al C++, mentre è altrettanto probabile che quelli che scrivevano in Java o C# venissero inclusi. Nel 1991, l'ereditarietà e la programmazione orientata agli oggetti erano una novità per la maggior parte dei programmatori. Ora questi sono concetti ben noti e le aree su cui le persone hanno bisogno di maggiori chiarimenti sono le eccezioni, i modelli e la programmazione generica. Nel 1991 nessuno aveva sentito parlare di design patterns. Ora, senza citarli, è generalmente difficile discuterne sistemi software. Nel 1991, il lavoro su uno standard C++ formale era appena iniziato, lo standard ora ha 8 anni e sono in corso i lavori sulla versione successiva.

Per tenere conto di tutti questi cambiamenti, ho deciso di iniziare tabula rasa e mi sono chiesto: "Che consiglio daresti ai programmatori C++ praticanti nel 2005?" Il risultato è un insieme di regole incluse nella nuova edizione. Questo libro include nuovi capitoli sulla programmazione dei modelli e sulla gestione delle risorse. In effetti, i modelli scorrono come un filo rosso attraverso il testo, poiché nel C++ moderno c'è poco senza di essi. Il libro include anche materiale sulla programmazione sotto eccezioni, modelli di progettazione e nuove strutture della biblioteca, descritto nella relazione tecnica 1 (TR1) (questo documento è trattato al punto 54). Riconosce inoltre il fatto che gli approcci e le tecniche che funzionano bene nei sistemi a thread singolo potrebbero non essere applicabili a quelli multi-thread. Più della metà dei materiali di questa edizione sono argomenti nuovi. Tuttavia, molte delle informazioni fondamentali della seconda edizione rimangono rilevanti, quindi ho trovato il modo di ripeterle in una forma o nell'altra (vedi appendice B per la corrispondenza tra le regole della seconda e della terza edizione).

Ho fatto del mio meglio per rendere questo libro il più utile possibile, ma ovviamente non penso che sia perfetto. Se ti sembra che alcune delle regole di cui sopra non possano essere considerate universalmente applicabili, che ci sia un modo migliore per risolvere il problema formulato, o che la discussione di alcuni problemi tecnici non abbastanza chiaro, incompleto, potrebbe essere fuorviante, per favore fatemelo sapere. Se trovi errori di qualsiasi tipo - tecnici, grammaticali, tipografici, qualunque cosa - fammi sapere anche quello. Nella prossima edizione sarò felice di citare chiunque porti un problema alla mia attenzione.

Nonostante nella nuova edizione il numero delle regole sia stato portato a 55, ovviamente, non si può dire che siano state considerate tutte e varie le questioni. Ma formulare un insieme di tali regole, che dovrebbero essere seguite quasi sempre in quasi tutte le applicazioni, è più difficile di quanto possa sembrare a prima vista. Se hai suggerimenti su cos'altro dovrebbe essere incluso, sarò felice di prenderli in considerazione.


Stafford, Oregon, aprile 2005

introduzione

Una cosa è studiare fondamentali lingua, e molto altro - per imparare a progettare e implementare programmi efficaci. Ciò è particolarmente vero per C++, noto per la sua straordinaria potenza ed espressività. Lavorare in C++, se usato correttamente, può essere divertente. Un'ampia varietà di progetti può essere espressa direttamente ed efficacemente implementata. Un insieme di classi, funzioni e modelli scelti con cura e ben implementati contribuirà a rendere un programma semplice, intuitivo, efficiente e praticamente privo di bug. Con le giuste competenze, scrivere programmi C++ efficaci non è affatto difficile. Tuttavia, se usato in modo inappropriato, C++ può produrre codice confuso, difficile da mantenere e semplicemente sbagliato.

Lo scopo di questo libro è mostrarti come usare C++ effettivamente. Presumo che tu abbia già familiarità con C++ come linguaggio di programmazione, e avere anche una certa esperienza con esso. Ti offro delle linee guida per l'utilizzo di questo linguaggio, che renderanno i tuoi programmi comprensibili, di facile manutenzione, portatili, estensibili, efficienti e che funzioneranno come previsto.

I consigli consigliati possono essere suddivisi in due categorie: strategia generale progettazione e uso pratico costrutti linguistici individuali. La discussione sui problemi di progettazione ha lo scopo di aiutarti a scegliere tra diversi approcci per risolvere un particolare problema in C++. Cosa scegliere: eredità o modelli? Eredità aperta o chiusa? Eredità chiusa o composizione? Funzioni dei membri o funzioni gratuite? Passando per valore o per riferimento? È importante prendere la decisione giusta fin dall'inizio, poiché le conseguenze di una scelta sbagliata potrebbero non manifestarsi fino a quando non è troppo tardi e rifare può essere difficile, dispendioso in termini di tempo e costoso.

Anche quando sai esattamente cosa vuoi fare, ottenere i risultati che desideri può essere difficile. Che tipo di valore deve restituire l'operatore di assegnazione? Quando dovrebbe essere virtuale un distruttore? Come si comporta il nuovo operatore se non riesce a trovare memoria sufficiente? È estremamente importante elaborare tali dettagli, perché altrimenti incontrerai quasi sicuramente comportamenti del programma inaspettati e persino inspiegabili. Questo libro ti aiuterà a evitare tali situazioni.

Naturalmente, questo libro è difficile da nominare. guida completa in C++. Piuttosto, è una raccolta dei loro 55 suggerimenti (o regole) per migliorare i tuoi programmi e progetti. Ogni paragrafo è più o meno indipendente dagli altri, ma la maggior parte ha riferimenti incrociati. Il modo migliore per leggere questo libro è iniziare con la regola che ti interessa di più e poi seguire i link per vedere dove ti portano.

Anche questo libro non è un'introduzione al C++. Nel Capitolo 2, ad esempio, parlo della corretta implementazione di costruttori, distruttori e operatori di assegnazione, ma presumo che tu sappia già cosa fanno queste funzioni e come vengono dichiarate. Ci sono molti libri C++ sull'argomento.

Bersaglio questo libri per evidenziare aspetti della programmazione C++ che sono spesso trascurati. Altri libri descrivono diverse parti della lingua. Descrive anche come combinarli tra loro per ottenere programmi efficaci. Altre pubblicazioni parlano di come ottenere un programma da compilare. E questo libro tratta di evitare problemi che il compilatore non può rilevare.

Allo stesso tempo, questo libro è limitato a standard C++. Qui vengono utilizzate solo le caratteristiche linguistiche descritte nello standard ufficiale. La portabilità è una questione chiave per questo libro, quindi se stai cercando trucchi specifici della piattaforma, cerca altrove.

Né troverai The Gospel of C++ in questo libro, l'unico modo sicuro per un perfetto programma C++. Ogni regola è una raccomandazione su un aspetto o sull'altro: come trovare un design migliore, come evitare errori comuni come ottenere la massima efficienza, ma nessuno dei punti è universalmente applicabile. La progettazione e lo sviluppo di software è un'attività complessa che è soggetta a vincoli hardware, sistema operativo e applicazioni, quindi il meglio che posso fare è immaginare raccomandazioni per migliorare la qualità dei programmi.

Se segui sistematicamente tutte le linee guida, è improbabile che ti imbatti nelle insidie ​​più comuni del C++, ma ci sono eccezioni a ogni regola. Ecco perché le spiegazioni sono fornite in ogni regola. Sono la parte più importante del libro. Solo comprendendo cosa sta alla base di questa o quella regola puoi decidere come si adatta al tuo programma con i suoi limiti.

Il modo migliore per usare questo libro è capire i segreti del comportamento del C++, capire perché si comporta in quel modo e usare il suo comportamento a proprio vantaggio. L'applicazione cieca nella pratica di tutte le regole di cui sopra è del tutto inappropriata, ma allo stesso tempo non si dovrebbe, senza motivi speciali, agire in contrasto con questi suggerimenti.

Terminologia

C'è un piccolo vocabolario C++ con cui ogni programmatore dovrebbe avere familiarità. I seguenti termini sono abbastanza importanti da avere senso assicurarsi di comprenderli allo stesso modo.

Annuncio(dichiarazione) dice al compilatore il nome e il tipo di qualcosa, omettendo alcuni dettagli. Gli annunci si presentano così:


interno x esterno; // dichiarazione dell'oggetto

std::size_t numDigits(numero int); // dichiarazione di funzione

widget di classe; // dichiarazione di classe

modello // modello di dichiarazione

classe GraphNode; // (Vedi regola 42 per sapere cosa sia "typename".


Nota che mi riferisco all'intero x come a un "oggetto" anche se è una variabile di tipo integrato. Alcune persone intendono solo variabili di tipo definite dall'utente con "oggetti", ma io non sono uno di loro. Si noti inoltre che la funzione numDigits() restituisce il tipo std::size_t, ovvero il tipo size_t dallo spazio dei nomi std. Questo è lo spazio dei nomi che contiene quasi tutto dalla libreria standard C++. Tuttavia, poiché la libreria standard C (più specificamente, C89) può essere utilizzata anche in un programma C++, i simboli ereditati da C (come size_t) possono esistere in contesto globale, all'interno di std o entrambi, a seconda dei file di intestazione inclusi con la direttiva #include. In questo libro, presumo che i file di intestazione C++ siano inclusi usando #include. Ecco perché uso std::size_t e non solo size_t. Quando menziono i componenti della libreria standard al di fuori del codice del programma, di solito ometto il riferimento a std, supponendo che tu sappia che cose come size_t, vector e cout si trovano nello spazio dei nomi std. Nei programmi di esempio, includo sempre std, perché altrimenti il ​​codice non verrà compilato.

A proposito, size_t è solo un alias definito da typedef per alcuni tipi senza segno che C++ usa per diverso tipo contatori (ad esempio, il numero di caratteri nelle stringhe char*, il numero di elementi nei contenitori STL, ecc.). È anche il tipo accettato dalle funzioni dell'operatore su vettori, deques e stringhe. Seguiremo questa convenzione quando definiamo le nostre funzioni operatore nella Regola 3.

Ogni dichiarazione di funzione ne specifica firma, ovvero i tipi dei parametri e il valore restituito. Possiamo dire che la firma di una funzione è il suo tipo. Pertanto, la firma della funzione numDigits è std::size_t(int), in altre parole, è "una funzione che prende un int e restituisce std::size_t". Definizione ufficiale Una "firma" in C++ non include il tipo restituito di una funzione, ma ai fini di questo libro sarà conveniente per noi presumere che faccia ancora parte della firma.

Definizione(definizione) dice al compilatore i dettagli che vengono omessi dalla dichiarazione. Per un oggetto, la definizione è dove il compilatore alloca memoria per esso. Per una funzione o un modello di funzione, la definizione contiene il corpo della funzione. La definizione di una classe o di un modello di classe elenca i suoi membri:


intx; // definizione dell'oggetto

std::size_t numDigits(int number) // definizione della funzione

( // (questa funzione restituisce il numero

std::size_t digitsSoFar = 1; // cifre decimali nel suo parametro)

while((numero /= 10) != 0) ++digitsSoFar;

restituisce digitsSoFar;

class Widget ( // definizione della classe

modello // definizione del modello

classe GraphNode(


Inizializzazione(inizializzazione) è il processo di assegnazione di un valore iniziale a un oggetto. Per gli oggetti di tipi definiti dall'utente, l'inizializzazione viene eseguita dai costruttori. Costruttore predefinito(costruttore predefinito) è un costruttore che può essere chiamato senza argomenti. Un tale costruttore non ha alcun parametro o ha un valore predefinito per ogni parametro:


UN(); // costruttore predefinito

esplicito B(int x = 0; bool b = vero); // costruttore predefinito,

// parola chiave "esplicita"

esplicito C(int x); // questo non è un costruttore

// predefinito


I costruttori delle classi B e C sono dichiarati con la parola chiave esplicita. Ciò impedisce che vengano utilizzati per conversioni di tipo implicito, sebbene non ne impedisca l'uso se la conversione è specificata in modo esplicito:


void fareQualcosa(B bOggetto); // La funzione prende un oggetto di tipo B

BbObj1; // oggetto di tipo B

fareQualcosa(bObj1); // ok, B è passato a fareSomething

bOggetto(28); // ok, crea B dall'intero 28

// (il parametro bool predefinito è true)

fareQualcosa(28); // errore! fareQualcosa accetta B,

// non int e non c'è alcun implicito

// conversione da int a B

fareQualcosa(B(28)); // ok, viene utilizzato il costruttore

// B per conversione esplicita (cast)

// int in B (vedi regola 27 per informazioni

// sul casting del tipo)


I costruttori dichiarati espliciti sono generalmente preferiti perché impediscono ai compilatori di eseguire conversioni di tipo implicite (spesso indesiderate). A meno che non ci sia una buona ragione per usare i costruttori nelle conversioni di tipo implicite, li dichiaro sempre espliciti. Ti consiglio di attenerti allo stesso principio.

Si noti che nell'esempio precedente il cast è evidenziato. Continuerò a usare questa enfasi per sottolineare l'importanza del materiale presentato. (Evidenzi anche i numeri dei capitoli, ma è solo perché penso che sia carino.)

costruttore di copie(costruttore di copia) viene utilizzato per inizializzare un oggetto con il valore di un altro oggetto dello stesso tipo, e operatore di assegnazione delle copie(operatore di assegnazione copia) viene utilizzato per copiare il valore di un oggetto in un altro - dello stesso tipo:


aggeggio(); // costruttore predefinito

Widget(const Widget&rhs); // copia il costruttore

Widget& operator=(const Widget& rhs); // operatore di assegnazione copia

Widget w1; // chiama il costruttore predefinito

Widget w2(w1); // chiama il costruttore di copie

w1 = w2; // Operatore di assegnazione chiamate

// copia


Fai attenzione quando vedi un costrutto simile a un compito, perché la sintassi "=" può essere utilizzata anche per invocare un costruttore di copia:


Widget w3 = w2; // chiama il costruttore di copie!


Fortunatamente, un costruttore di copie è facile da distinguere da un'assegnazione. Se viene definito un nuovo oggetto (come w3 nell'ultima frase), è necessario chiamare il costruttore, non può essere un compito. Se non viene creato alcun nuovo oggetto (come in "w1=w2"), non viene applicato alcun costruttore ed è un'assegnazione.

Il costruttore di copia è una caratteristica particolarmente importante perché definisce come un oggetto viene passato per valore. Ad esempio, considera il seguente snippet:


bool hasAcceptableQuality(Widget w);

if (hasAcceptableQuality(aWidget)) ...


Il parametro w viene passato alla funzione hasAcceptableQuality in base al valore, quindi nella chiamata di esempio precedente aWidget viene copiato in w. La copia viene eseguita dal costruttore di copia dalla classe Widget. In generale, passa per valore si intende chiamando il costruttore di copia. (Ma a rigor di termini, il passaggio di tipi personalizzati per valore è cattiva idea. Di solito è meglio passare per riferimento a una costante, vedere la voce 20 per i dettagli.)

STL– la Standard Template Library è la parte della libreria standard che si occupa di contenitori (es. vector, list, set, map, ecc.), iteratori (es. vector::iterator, set::iterator, ecc.). ecc.) , algoritmi (ovvero for_each, trova, ordina, ecc.) e tutte le relative funzionalità. È ampiamente usato oggetti funzione(oggetti funzione), ovvero oggetti che si comportano come funzioni. Tali oggetti sono rappresentati da classi in cui l'operatore di chiamata operator() è sovraccaricato. Se non hai dimestichezza con l'STL, oltre a questo libro avrai bisogno di una buona guida sull'argomento, perché l'STL è così pratico che sarebbe imperdonabile non approfittarne. Basta iniziare a lavorarci e tu stesso lo sentirai.

I programmatori che arrivano in C++ da linguaggi come Java o C# possono trovare il concetto di comportamento indefinito. Per vari motivi, il comportamento di alcuni costrutti in C++ è davvero indefinito: non è possibile prevedere con certezza cosa accadrà in fase di esecuzione. Ecco due esempi di questo tipo:


int *p = 0; // p è un puntatore nullo

char name = "Daria" // name è un array di lunghezza 6 (non dimenticare

// terminazione null!)

carattere c = nome; // specificando un indice di matrice errato

// genera un comportamento indefinito


Per sottolineare che i risultati di un comportamento indefinito sono imprevedibili e possono essere piuttosto spiacevoli, i programmatori C++ esperti spesso affermano che i programmi con un comportamento indefinito possono cancellare il contenuto di un disco rigido. È vero che un tale programma può essere cancella il tuo HDD, ma potrebbe non farlo. È più probabile che si comporti in modo diverso: a volte funzionerà bene, a volte si arresterà in modo anomalo ea volte darà solo risultati errati. I programmatori Wise C++ seguono la regola di evitare comportamenti indefiniti. In questo libro, in molti luoghi, indico come farlo.

Un altro termine che potrebbe confondere i programmatori provenienti da altre lingue è interfaccia. In Java e. Nei linguaggi compatibili con NET, le interfacce fanno parte del linguaggio, ma C++ non ha nulla del genere, anche se l'articolo 31 discute alcune approssimazioni. Quando uso il termine "interfaccia" di solito intendo firme di funzioni, membri accessibili della classe ("interfaccia pubblica", "interfaccia protetta", " interfaccia privata”) o espressioni consentite come parametri di tipo per i modelli (vedi punto 41). Cioè, per interfaccia, capisco il concetto generale di design.

concetto clienteè qualcosa o qualcuno che utilizza il codice che scrivi (di solito tramite interfacce). Quindi, ad esempio, i client di una funzione sono i suoi utenti: i pezzi di codice che chiamano la funzione (o prendono il suo indirizzo), così come le persone che scrivono e mantengono tale codice. I client di una classe o di un modello sono le parti del programma che utilizzano la classe o il modello, nonché i programmatori che scrivono o mantengono tali parti. Quando si tratta di clienti, di solito mi riferisco ai programmatori, perché sono quelli che possono essere fuorviati o insoddisfatti con un'interfaccia mal progettata. Il codice che scrivono non ha quel tipo di emozione.

Forse non sei abituato a pensare ai clienti, ma cercherò di convincerti della necessità di rendere loro la vita il più facile possibile. Dopotutto, tu stesso sei un cliente di software che è stato sviluppato da qualcun altro. Dopotutto, vorresti che i suoi autori rendessero il tuo lavoro più semplice? Inoltre, prima o poi ti ritroverai in una posizione in cui diventerai tu stesso un cliente del tuo stesso codice (ovvero utilizzerai il codice che scrivi tu), e quindi apprezzerai che quando si progettano le interfacce, è necessario mantenere il in mente gli interessi dei clienti.

In questo libro, attiro spesso l'attenzione sulla distinzione tra funzioni e modelli di funzione e tra classi e modelli di classe. Non è un caso, perché ciò che è vero per uno è spesso vero per un altro. In situazioni in cui questo non è il caso, faccio una distinzione tra classi, funzioni e modelli da cui derivano classi e funzioni.

Convenzioni di denominazione

Ho provato a scegliere nomi significativi per oggetti, classi, funzioni, modelli e così via, ma la semantica di alcuni dei nomi che ho inventato potrebbe non essere ovvia per te. Ad esempio, uso spesso i nomi lhs e rhs per i parametri. Questo si riferisce rispettivamente al "lato sinistro" (lato sinistro) e al "lato destro" (lato destro). Questi nomi vengono solitamente utilizzati nelle funzioni che implementano operatori binari, ovvero operator== e operator*. Ad esempio, se aeb sono oggetti che rappresentano numeri razionali e se gli oggetti della classe Rational possono essere moltiplicati usando la funzione operator*() non membro (un caso simile è descritto nell'Elemento 24), allora l'espressione



è equivalente a una chiamata di funzione:


operatore*(a, b);


Al punto 24 dichiaro operatore* in questo modo:


const Operatore razionale*(const Rational& lhs, const Rational& rhs);


Come puoi vedere, l'operando sinistro - a - all'interno della funzione è chiamato lhs e quello destro - b - rhs.

Per le funzioni membro, l'argomento sul lato sinistro dell'operatore è rappresentato dal puntatore this e l'unico parametro rimanente che a volte chiamo rhs. Potresti averlo notato nella dichiarazione di alcune delle funzioni dei membri della classe Widget negli esempi precedenti. "Widget" non significa nulla. È solo un nome che a volte uso per dare un nome a una classe di esempio. Non ha nulla a che fare con i controlli (widget) utilizzati in interfacce grafiche(GUI).

Spesso nomino i puntatori seguendo la convenzione che un puntatore a un oggetto di tipo T è chiamato pt ("puntatore a T"). Ecco alcuni esempi:


Widget *pw; // pw = puntatore al widget

Aereo *pa; // pa = puntatore all'aereo

personaggio del gioco di classe;

Personaggio del gioco *pgc; // pgc = puntatore a GameCharacter


Una convenzione simile si applica ai collegamenti: rw può essere un collegamento Widget e ra può essere un collegamento aereo.

A volte uso il nome mf per nominare una funzione membro.

Multithreading

Nello stesso linguaggio C++, non esiste il concetto di thread (thread), e in effetti di qualsiasi meccanismo per l'esecuzione parallela. Lo stesso vale per la libreria standard C++. In altre parole, dal punto di vista del C++, non esistono programmi multithread.

Tuttavia, lo sono. Sebbene in questo libro parlerò principalmente di C++ standard e portatile, è impossibile ignorare il fatto che la sicurezza dei thread è un requisito che molti programmatori devono affrontare. Riconoscendo questo conflitto tra C++ standard e realtà, prenderò nota dei casi in cui i costrutti in questione possono causare problemi durante l'esecuzione in un ambiente multithread. Non pensare che questo libro ti insegnerà come programmare in multithread C++. Affatto. Ho preso in considerazione principalmente le applicazioni a thread singolo, ma non ho ignorato l'esistenza del multithreading e ho cercato di evidenziare i casi in cui i programmatori che scrivono programmi multithread dovrebbero seguire con attenzione i miei consigli.

Se non hai familiarità con il concetto di multithreading e non sei interessato a questo argomento, puoi ignorare le note ad esso correlate. Altrimenti, tieni presente che i miei commenti non sono altro che un modesto suggerimento di ciò che devi sapere se utilizzerai C++ per scrivere programmi multithread.

Librerie TR1 e Boost

In questo libro vedrai riferimenti alle librerie TR1 e Boost. Ognuno di loro ha una regola separata (54 - TR1 e 55 - Boost), ma, sfortunatamente, sono proprio alla fine del libro. Puoi leggerli subito se lo desideri, ma se preferisci leggere il libro in ordine piuttosto che dalla fine, le seguenti note ti aiuteranno a capire la posta in gioco:

TR1 ("Rapporto tecnico 1") è una specifica per nuove funzionalità aggiunte libreria standard C++. È incluso in nuovi modelli di classe e funzioni per implementare tabelle hash, puntatori intelligenti con conteggio dei riferimenti, espressioni regolari e altro ancora. Tutti i componenti TR1 si trovano nello spazio dei nomi tr1, che è nidificato nello spazio dei nomi std.

Boost è un'organizzazione e un sito Web (http://boost.org) che offre librerie C++ open source portatili e rigorosamente testate. codice sorgente. Gran parte di TR1 si basa sul lavoro svolto da Boost e fino a quando i fornitori di compilatori non includeranno TR1 nelle distribuzioni C++, il sito Web Boost continuerà a essere la principale fonte di implementazioni di TR1 per gli sviluppatori. Boost fornisce più di ciò che è incluso in TR1, ma è comunque utile saperlo.

Abituati al C++

Indipendentemente dall'esperienza di programmazione, ci vuole del tempo per familiarizzare con C++. È un linguaggio potente con un molto vasta gamma opportunità, ma per utilizzarle in modo efficace, devi cambiare un po' il tuo modo di pensare. Questo libro è progettato per aiutarti a fare proprio questo, ma alcune domande sono più importanti di altre e questo capitolo tratta le cose più importanti.

Regola 1: tratta il C++ come un conglomerato di linguaggi

All'inizio, C++ era solo un linguaggio C con alcune funzionalità orientate agli oggetti inserite. Anche il nome originale di C++ ("C con classi") riflette questa connessione.

Man mano che il linguaggio è maturato, è cresciuto e si è evoluto per includere idee e strategie di programmazione che vanno oltre il C con le classi. Le eccezioni richiedevano un approccio diverso alla strutturazione delle funzioni (vedi regola 29). I modelli hanno cambiato il modo in cui pensiamo alla progettazione del software (vedi punto 41) e l'STL ha definito un approccio all'estendibilità che nessuno avrebbe potuto immaginare prima.

Oggi C++ è il linguaggio programmazione con più paradigmi, supporto procedurale, orientato agli oggetti, funzionale, generico e metaprogrammazione. Questa potenza e flessibilità rendono C++ uno strumento incomparabile, ma può creare confusione. Qualsiasi raccomandazione per corretta applicazione» ci sono delle eccezioni. Come trovare un significato in una lingua del genere?

È meglio pensare al C++ non come un linguaggio, ma come un conglomerato di linguaggi correlati. All'interno di una singola sottolingua, le regole sono abbastanza semplici, comprensibili e facili da ricordare. Tuttavia, mentre ti sposti da una sottolingua all'altra, le regole potrebbero cambiare. Per dare un senso al C++, devi riconoscere i suoi principali sottolinguaggi. Fortunatamente, ce ne sono solo quattro:

C. Fondamentalmente, C++ è ancora basato su C. I blocchi, le clausole, il preprocessore, i tipi di dati incorporati, gli array, i puntatori e così via provengono tutti da C. In molti casi, C++ fornisce meccanismi più avanzati per risolvere determinati problemi, rispetto a C (per un esempio, vedere Regola 2 - L'alternativa al preprocessore e 13 - Usare gli oggetti per gestire le risorse), ma quando inizi a lavorare con la parte di C++ che ha controparti in C, ti renderai conto che le regole della programmazione efficiente riflettono la natura più limitata del linguaggio C: nessun carattere jolly, nessuna eccezione, nessun sovraccarico, ecc.

C++ orientato agli oggetti. Questa parte di C++ rappresenta ciò che era "C con classi", inclusi costruttori e distruttori, incapsulamento, ereditarietà, polimorfismo, funzioni virtuali(collegamento dinamico), ecc. Questa è la parte di C++ che maggior parte si applicano le regole classiche del design orientato agli oggetti.

C++ con modelli. Questa parte di C++ è chiamata programmazione generica e la maggior parte dei programmatori ne sa poco. I modelli ora permeano il C++ dall'alto verso il basso ed è già un segno di buona pratica di programmazione includere costrutti impensabili senza modelli (ad esempio, vedere l'articolo 46 sulla conversione del tipo nelle chiamate a funzioni di modello). In effetti, i modelli, grazie alla loro potenza, hanno generato un paradigma di programmazione completamente nuovo: metaprogrammazione dei modelli(metaprogrammazione di modelli - TMP). L'articolo 48 fornisce una panoramica di TMP, ma a meno che tu non sia un fanatico irriducibile dei modelli, non hai motivo di pensarci troppo. TMP non è una delle tecniche di programmazione C++ più comuni.

STL. STL è, ovviamente, una libreria di modelli, ma molto specializzata. Le sue convenzioni per contenitori, iteratori, algoritmi e oggetti funzione funzionano bene insieme, ma i modelli e le librerie possono essere costruiti in modo diverso. Quando si lavora con la libreria STL, è necessario seguire le sue convenzioni.

Tieni a mente queste quattro sottolingua e non sorprenderti se ti trovi in ​​una situazione in cui considerazioni di efficienza richiedono di cambiare strategia quando passi da una sottolingua all'altra. Ad esempio, per i tipi predefiniti (nello stile C), passando i parametri per valore in caso generaleè più efficiente del passaggio per riferimento, ma se stai programmando in uno stile orientato agli oggetti, la presenza di costruttori e distruttori definiti dall'utente di solito rende più efficiente il passaggio per riferimento a una costante. Ciò è particolarmente vero per il sottolinguaggio "C++ con modelli", perché di solito non si conosce nemmeno in anticipo il tipo di oggetti con cui si ha a che fare. Ma ora sei passato all'uso dell'STL, e ancora una volta entra in gioco la vecchia regola C sul passaggio per valore, perché gli iteratori e gli oggetti funzione sono modellati in termini di puntatori C. (Vedi Regola 20 per ulteriori informazioni sulla scelta di come passare parametri.)

Pertanto, C++ non è un linguaggio omogeneo con un unico insieme di regole. È un conglomerato di sottolinguaggi, ciascuno con le proprie convenzioni. Se tieni a mente questi sottolinguaggi, scoprirai che C++ è molto più facile da capire.

Cose da ricordare

Le regole per una programmazione efficace cambiano a seconda della parte di C++ che stai usando.

Regola 2: preferisci const, enum e inline su #define

Questa regola sarebbe meglio chiamata "Compiler over preprocessor" perché #define spesso non è affatto considerato un linguaggio C++. Qui sta il problema. Considera un semplice esempio; prova a scrivere qualcosa come:


#define RAPPORTO_ASPETTO 1.653


Il nome simbolico ASPECT_RATIO può rimanere sconosciuto al compilatore o essere rimosso dal preprocessore prima che il codice venga elaborato dal compilatore. Se ciò accade, il nome ASPECT_RATIO non entrerà nella tabella dei simboli. Pertanto, durante la compilazione, riceverai un errore (il valore 1.653 sarà menzionato nel messaggio di errore, non ASPECT_RATIO). Ciò causerà confusione. Se il nome ASPECT_RATIO è stato definito in un file di intestazione che non hai scritto, non saprai affatto da dove viene il valore 1.653 e passerai molto tempo a cercare una risposta. Lo stesso problema può verificarsi anche durante il debug, perché il nome scelto non sarà nella tabella dei simboli.

La soluzione è sostituire la macro con una costante:


const double AspectRatio = 1,653; // nomi scritti lettere maiuscole,

// solitamente usato per le macro,

// quindi abbiamo deciso di cambiarlo


Essendo una costante del linguaggio, AspectRatio è visibile al compilatore ed è naturalmente inserito nella tabella dei simboli. Inoltre, l'utilizzo di una costante in virgola mobile (come in questo esempio) genera un codice più compatto rispetto all'utilizzo di #define. Il fatto è che il preprocessore, sostituendo alla cieca il valore 1.653 invece della macro ASPECT_RATIO, crea molte copie di 1.653 nel codice oggetto, mentre l'utilizzo di una costante non genererà mai più di una copia di questo valore.

Quando si sostituisce # definire costanti due cose da ricordare occasioni speciali. Il primo riguarda i puntatori costanti. Poiché le definizioni delle costanti vengono solitamente inserite nei file di intestazione (dove vi accedono molti file sorgenti), è importante che puntatoreè stato dichiarato con la parola chiave const, oltre alla dichiarazione const di ciò a cui punta. Ad esempio, per dichiarare una stringa costante di tipo char* in un file di intestazione, è necessario scrivere la parola const due volte:


const char * const authorName = "Scott Meyers";


Per ulteriori informazioni sulla natura e gli usi della parola const, specialmente in relazione ai puntatori, vedere l'elemento 3. Ma per ora, vale la pena ricordare che gli oggetti di tipo string sono generalmente preferiti ai loro antenati - stringhe di tipo char *, quindi è meglio definire authorName in questo modo:


const std::string nomeautore("Scott Meyers");


La seconda osservazione riguarda le costanti dichiarate come parte di una classe. Per estendere una costante a una classe, devi renderla un membro della classe e per assicurarti che ci sia solo una copia della costante, devi renderla statico membro:


classGamePlayer(

static const int NumTurns = 5; // dichiarazione costante

punteggi int; // usando una costante


Quello che vedi sopra lo è annuncio NumTurns, non la sua definizione. C++ normalmente richiede di fornire una definizione per tutto ciò che usi, ma le costanti dichiarate in una classe che sono statiche e hanno un tipo integrato (cioè intero, carattere, booleano) sono l'eccezione alla regola. Finché non stai cercando di ottenere l'indirizzo di una tale costante, puoi dichiararla e usarla senza fornire una definizione. Se hai bisogno di ottenere l'indirizzo, o se il tuo compilatore insiste su una definizione, puoi scrivere qualcosa del genere:


const int GamePlayer::NumTurns; // definisce NumTurn; vedi sotto,

// perché il valore non è specificato


Inserisci questo codice nel file di implementazione, non nel file di intestazione. Poiché il valore iniziale di una costante di classe è presente dove viene dichiarata (ovvero, NumTurns viene inizializzato a 5 quando viene dichiarato), non è necessario specificare un valore iniziale nel punto di definizione.

Nota, a proposito, che non è possibile dichiarare una costante in una classe con #define, perché #define non è sensibile all'ambito. Una volta definita una macro, rimane attiva per il resto del codice compilato (a meno che #undef non si trovi da qualche parte sotto). Ciò significa che la direttiva #define non è solo inapplicabile per la dichiarazione di costanti in una classe, ma non può essere utilizzata per fornire alcun tipo di incapsulamento, ovvero è impossibile dare un senso all'espressione "private #define". Allo stesso tempo, è possibile incapsulare membri di dati costanti, ad esempio NumTurns.

I compilatori precedenti potrebbero non supportare la sintassi mostrata sopra perché le versioni precedenti del linguaggio non consentivano di impostare valori statici dei membri della classe al momento della dichiarazione. Inoltre, l'inizializzazione in una classe era consentita solo per i tipi interi e per le costanti. Se la sintassi precedente non funziona, è necessario specificare il valore iniziale nella definizione:


classe CostStima(

statico const double FudgeFactor; // dichiarazione costante statica

... // classe - inserita nel file di intestazione

const double // definizione costante statica

CostEstimate::FudgeFactor = 1,35; // classe - inserita nel file di implementazione


Di solito non serve altro. L'unica eccezione è quando è necessaria una costante per compilare la classe. Ad esempio, quando si dichiara un array GamePlayer::scores, il compilatore deve conoscere la dimensione dell'array. Per lavorare con un compilatore che vieta erroneamente di inizializzare costanti intere statiche all'interno di una classe, puoi usare una tecnica nota come "trucco enum". Si basa sul fatto che le variabili enumerate possono essere utilizzate dove sono previsti valori int, quindi GamePlayer può essere definito in questo modo:


classGamePlayer(

enum(NumTurns = 5 ); // "trucco per l'enumerazione" - fa da

// Carattere NumTurns con valore 5

punteggi int; // bene


Vale la pena conoscere questa tecnica per diversi motivi. Primo, il comportamento del "trucco enum" è per certi aspetti più simile a una #define che a una costante, ea volte è esattamente quello che vuoi. Ad esempio, puoi ottenere l'indirizzo di una costante, ma non puoi ottenere l'indirizzo di un enum, così come non puoi ottenere l'indirizzo di #define. Se si desidera impedire di ottenere un indirizzo o un riferimento a una costante intera, utilizzare enum è un buon modo per imporre tale restrizione. (Vedere l'articolo 18 per ulteriori informazioni sul supporto dei vincoli di progettazione con le tecniche di codifica.) Inoltre, mentre i buoni compilatori non allocano memoria per oggetti const di tipo intero (a meno che tu non stia creando un puntatore o un riferimento a un oggetto), i compilatori meno sofisticati potrebbero farlo e potresti non volerlo. Come #define , le enumerazioni non causeranno mai questo tipo di allocazione di memoria indesiderata.

La seconda ragione per conoscere il "trucco dell'enumerazione" è puramente pragmatica. È usato in così tanti programmi, quindi devi essere in grado di riconoscere questo trucco quando lo incontri. In generale, questo trucco è una tecnica fondamentale utilizzata nella metaprogrammazione dei modelli (vedi punto 48).

Torniamo al preprocessore. Un altro uso improprio comune della direttiva #define consiste nel creare macro che sembrano funzioni ma non sono gravate dal sovraccarico delle funzioni di chiamata. Di seguito è riportata una macro che chiama una funzione f con un argomento uguale al massimo di due valori:


// chiama f, passandogli il massimo di a e b

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


Ci sono così tanti difetti in questa linea che non è nemmeno del tutto chiaro da dove cominciare.

Ogni volta che scrivi una macro come questa, devi ricordare che tutti gli argomenti devono essere racchiusi tra parentesi. Altrimenti, corri il rischio di metterti nei guai quando qualcuno lo chiama con un'espressione come argomento. Ma anche se fai tutto bene, guarda cosa possono succedere cose strane:


int a = 5, b = 0;

CALL_WITH_MAX(++a, b); // a viene incrementato due volte

CALL_WITH_MAX(++a, b+10); // a viene incrementato una volta


Ciò che accade all'interno di max dipende da cosa viene confrontato!

Fortunatamente, non devi sopportare comportamenti che sfuggono a tanta logica. Esiste un metodo che consente di ottenere la stessa efficienza dell'utilizzo del preprocessore. Ma allo stesso tempo, fornisce sia un comportamento prevedibile che il controllo dei tipi di argomenti (che è tipico per le funzioni ordinarie). Questo risultato si ottiene utilizzando il modello di funzione in linea (vedi punto 30):


inline void callWithMax(const T& a, const T& b) // Dal momento che non lo sappiamo

( // cos'è T, quindi passiamo

) // vedi paragrafo 20


Questo modello genera un'intera famiglia di funzioni, ognuna delle quali accetta due argomenti dello stesso tipo e chiama f con il più grande di essi. Non è necessario mettere tra parentesi i parametri all'interno del corpo della funzione, non è necessario preoccuparsi della valutazione dei parametri più volte, ecc. Inoltre, poiché callWithMax è una funzione reale, è soggetta a regole di scoping e controllo degli accessi. Ad esempio, puoi parlare di una funzione incorporata che è un membro privato di una classe. È impossibile descrivere qualcosa di simile usando una macro.

La presenza di const, enum e inline riduce drasticamente la necessità di un preprocessore (soprattutto con #define), ma non lo elimina del tutto. La direttiva #include rimane essenziale e #ifdef/#ifndef continuano a svolgere un ruolo importante nel controllo della compilazione. Non è ancora il momento di abbandonare il preprocessore, ma vale sicuramente la pena considerare come liberarsene in futuro.

Cose da ricordare

Per le costanti semplici, la direttiva #define dovrebbe preferire oggetti const ed enum.

Invece di imitare le macro definite con #define, è meglio usare le funzioni integrate.

Regola 3: usa const ove possibile

La cosa bella del modificatore const è che impone un certo vincolo semantico: l'oggetto dato non deve essere modificato e il compilatore imporrà quel vincolo. const ti consente di dire al compilatore e ai programmatori che un certo valore dovrebbe rimanere invariato. In tutti questi casi, devi indicarlo esplicitamente, chiamando il compilatore per aiutarti e assicurandoti così che il vincolo non venga violato.


Questa sintassi non è così spaventosa come potrebbe sembrare. Se la parola const appare a sinistra dell'asterisco, ciò a cui punta il puntatore è const; se a destra, il puntatore stesso è const. Infine, se la parola const compare su entrambi i lati, allora entrambi sono costanti.

Appunti

C'è una traduzione russa: Sutter stemma. Risolvere problemi complessi in C++. Williams Publishing House, 2002 (nota scientifica ed.).

C'è una traduzione russa: modelli di design. San Pietroburgo: Peter (circa ed. scientifico).

Fine della prova gratuita.

  • Pagine:
    , ,
  • Feedback sulla terza edizione
    Uso efficace del C++

    libro di scott meyers Usare C++ in modo efficace, terza edizioneè la concentrazione dell'esperienza di programmazione - l'esperienza che senza di essa sarebbe arrivata a un prezzo elevato. Questo libro è un'ottima fonte che consiglio a chiunque scriva C++ in modo professionale.

    Peter Dulimov, ME, Ingegnere, Unità di valutazione e ricerca NAVSYSCOM, Australia

    La terza edizione rimane il miglior libro su come mettere insieme tutti i pezzi di C++ per creare programmi efficienti e internamente coerenti. Se stai fingendo di essere un programmatore C++, dovresti leggerlo.

    Eric Nagler, consulente, docente e autore di Learning C++

    La prima edizione di questo libro era uno dei pochi (pochissimi) libri che hanno davvero migliorato il mio livello di sviluppatore di software professionista. Come altri libri di questa serie, era pratico e di facile lettura, ma conteneva anche molti consigli importanti. "Uso efficace C++", terza edizione, continua questa tradizione. C++ è un linguaggio di programmazione molto potente. Se C ti dà una corda per scalare la cima di una montagna, allora C++ è un negozio pieno di tutti i tipi di persone che sono disposte ad aiutarti a fare nodi su quella corda. Padroneggiare il materiale in questo libro aumenterà sicuramente la tua capacità di usare il C++ in modo efficace e non morirai per lo sforzo.

    Jack W. Reeves, CEO di Bleading Edge Software Technologies

    Ogni nuovo sviluppatore che entra a far parte del mio team riceve immediatamente il compito di leggere questo libro.

    Michael Lanzetta, Capo Ingegnere Software

    Ho letto la prima edizione di Effective C++ circa 9 anni fa ed è diventato rapidamente uno dei miei libri C++ preferiti. A mio parere, Using C++ Effectively 3rd Edition rimane una lettura obbligata per chiunque voglia programmare efficacemente in C++. Vivremo in un mondo migliore se i programmatori C++ leggeranno questo libro prima di scrivere la prima riga di codice professionale.

    Danny Rabbani, ingegnere informatico

    La prima edizione di The Effective Use of C++ di Scott Meyers mi è venuta in mente quando ero un normale programmatore e mi sono sforzato di fare il miglior lavoro che mi era stato assegnato. Ed è stato un toccasana! Ho scoperto che il consiglio di Meyers è pratico ed efficace, che mantiene al 100% ciò che promette. La terza edizione ti aiuta ad applicare il C++ ai seri progetti software di oggi, fornendo informazioni sugli strumenti e le funzionalità più recenti del linguaggio. Sono stato felice di scoprire che potevo trovare molte cose nuove e interessanti per me stesso nella terza edizione di un libro che pensavo di conoscere molto bene.

    Michael Argomento, responsabile del programma tecnico

    Questa è un'autorevole guida di Scott Meyers, guru del C++, per chiunque desideri utilizzare il C++ in modo sicuro ed efficiente, o per chi sta effettuando la transizione al C++ da qualsiasi altro linguaggio orientato agli oggetti. Questo libro contiene informazioni preziose presentate in uno stile chiaro, conciso, divertente e perspicace.

    Siddhartha Karan Singh, sviluppatore di software

    Grazie

    L'uso efficace di C++ è in circolazione da 15 anni e ho iniziato a imparare il C++ circa 5 anni prima di scriverlo. Pertanto, il lavoro su questo progetto va avanti da circa 20 anni. Durante questo periodo ho ricevuto desideri, commenti, correzioni e talvolta osservazioni sbalorditive da centinaia (migliaia?) di persone. Ognuno di loro ha contribuito a sviluppare "Usare C++ in modo efficace". Sono grato a tutti loro.

    Ho smesso di cercare di ricordare dove e cosa ho imparato molto tempo fa, ma non posso fare a meno di menzionare una fonte perché la uso sempre. Questi sono i newsgroup di Usenet, in particolare comp.lang.c++.moderated e comp.std.c++. Molte delle regole in questo libro (forse la maggior parte) sono nate come risultato del pensiero sulle idee tecniche discusse in questi gruppi.

    Steve Dewhurst mi ha aiutato a selezionare nuovo materiale per la terza edizione del libro. Nell'articolo 11, l'idea di implementare l'operatore operator= tramite copia e scambio è tratta dagli appunti di Herb Sutter, in particolare dal Problema 13 del suo libro Exceptional C++ (Addison-Wesley, 2000). L'idea di acquisire una risorsa come inizializzazione (Regola 13) viene da The C++ Programming Language (Addison-Wesley, 2002) di Bjarne Stroustrup. L'idea alla base della regola 17 è tratta dalla sezione "Best practices" del sito web Boost shared_ptr (http://boost.org/libs/smart_ptr/shared_ptr.htm#BestPractices) e perfezionata sulla base del materiale del problema 21 nel libro Herb Sutter "C++ più eccezionale" (Addison-Wesley, 2002). La regola 29 è stata ispirata dall'ampia esplorazione di Herb Sutter di questo argomento nei problemi 8-19 del C++ eccezionale, nonché dai problemi 17-23 del C++ più eccezionale e dai problemi 11-13 del suo libro C++ eccezionale. Stile" (Addison-Wesley, 2005). David Abrahams mi ha aiutato a comprendere meglio i tre principi per garantire la sicurezza delle eccezioni. Il linguaggio dell'interfaccia non virtuale (NVI) nel punto 35 è tratto dalla colonna "Virtuality" di Herb Sutter nel numero di settembre 2001 del C/C++ Users Journal. I design patterns "Template Method" e "Strategy" citati nella stessa regola sono tratti dal libro "Design Patterns" (Addison-Wesley, 1995) di Erich Gamma, Richard Helm, Ralph Johnson (Ralf Johnson) e John Vlissides (John Vlisside). L'idea di utilizzare l'idioma NVI nella regola 37 è stata suggerita da Hendrik Schober. Il contributo di David Smallberg è l'implementazione dell'insieme descritta nell'articolo 38. L'osservazione fatta nell'articolo 39 che l'ottimizzazione di una classe base vuota è fondamentalmente impossibile con l'ereditarietà multipla è tratta dal libro di David Vandevoorde e Nicholas M. Jossuthis (Nickolai M. Josuttis) "Modelli C++" (Addison-Wesley, 2003). Nell'articolo 42, la mia idea iniziale di cosa serva la parola chiave typename si basa sulle FAQ C++ e C ( http://www.comeaucomputing.com/techtalk/#typename) mantenuto da Greg Comeau, e Leor Zolman mi ha aiutato a capire che questo punto di vista è sbagliato (colpa mia, non di Greg). Il tema della regola 46 è venuto dal discorso "Come fare nuove amicizie" di Dan Saks. L'idea alla fine della regola 52, che se dichiari una versione di new, devi dichiarare tutte le altre, è esposta nel problema 22 del C++ eccezionale di Herb Sutter. La mia comprensione del processo di revisione Boost (riassunto al punto 55) è stata chiarita da David Abrahams.

    Tutto quanto sopra riguarda dove e da chi sono stato io a imparare qualcosa, indipendentemente da chi ha pubblicato per primo il materiale sull'argomento in questione.

    I miei appunti affermano anche che ho utilizzato informazioni di Steve Clamage, Antoine Trux, Timothy Knox e Mike Kaelbling, anche se sfortunatamente non è specificato dove e come.

    Bozze della prima edizione recensite da Tom Cargill, Glenn Carroll, Tony Davis, Brian Kernigan, Jak Kirman, Doug Lea, Moises Lejter), Eugene Santos Jr. (Eugene Santos, Jr), John Shewchuk, John Stasko, Bjarne Stroustrup, Barbara Tilly e Nancy L. Urbano. Inoltre, le richieste di miglioramenti che sono state incluse nelle edizioni successive sono state avanzate da 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 Trax, Cade Roux, Chandrika Gokul, Randy Mangoba e Glenn Teitelbaum.

    Bozze della seconda edizione recensite da: Derek Bosch, Tim Johnson, Brian Kernighan, Junichi Kimura, Scott Lewandowski, Laura Michaels, David Smallberg, Clovis Tonado, Chris Van Wyk e Oleg Zabluda. Le edizioni successive hanno beneficiato del commento di Daniel Steinberg, Arunprasad Marathe, Doug Stapp, Robert Hall, Cheryl Ferguson, Gary Bartlett, Michael Tamm (Michael Tamm), Kendall Beaman, Eric Nagler, Max Hailperin, Joe Gottman, Richard Weeks, Valentin Bonnard, Jun Hee, Tim King, Don Mailer, Ted Hill, Marc Harrison, Michael Rubinstein, Marc Rodgers, David Goh, Brenton Cooper, Andy Thomas-Cramer, Anton Thrax, John Walt, Brian Sharon, Liam Fitzpatric, Bernd Mohr, Harry Yee (Gary Yee), John O "Hanley (John O" Hanley), Brady Patreson (Brady Paterson), Christopher Peterson (Christ 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 Blonqvist, Jimmy Snyder, Birial Jensen, Witold Kuzminski, Kazunobu Kuriyama, Michael Christensen, Jorge Yanez Teruel, Mark Davis, Marty Rabinowitz, Ares Lagae e Alexander Medvedev.

    Le prime bozze parziali di questa edizione sono state riviste da: Brian Kernighan, Angelique Langer, Jesse Luchley, Roger P. Pedersen, Chris Van Wyck, Nicholas Stroustrup e Hendrik Schober. Recensione della bozza completa recensita da: Leor Zolman, Mike Tsao, Eric Nagler, Gene Gutnick, David Abrahams, Gerhard Kreuser, Drosos Kouronis, Brian Kernighan, Andrew Krims, Balogh Pal, Emily Jagdhar, Evgeny Kalenkovic, Mike Rose, Enrico Carrara, Benjamin Burke , Jack Reeves, Steve Schirippa, Martin Fallenstedt, Timothy Knox, Yun Bai, Michael Lanzetta, Philip Janert, Judo Bartolucci, Michael Topic, Jeff Sherpeltz, Chris Nauroth, Nishant Mittal, Jeff Sommers, Hal Moroff, Vincent Manis, Brendon Chang, Greg Lee, Jim Meehan, Alan Geller, Siddhartha Singh, Sam Lee, Sasan Dashtinejad, Alex Martin, Steve Kai, Thomas Fruchterman, Corey Hicks, David Smallberg, Gunawardan Kakulapati, Danny Rabbani, Jake Cohen, Hendrik Schuber, Paco Viziana, Glenn Kennedy Jeffrey D. Oldham, Nicholas Stroustrup, Matthew Wilson, Andrei Alexandrescu, Tim Johnson, Leon Matthews, Peter Dulimov e Kevlin Henney. Le bozze di alcuni singoli paragrafi sono state riviste anche da Herb Sutter e Attila F. Feher.

    Revisionare un manoscritto grezzo (e forse incompleto) è un lavoro duro e le scadenze strette lo rendono solo più difficile. Ringrazio tutti coloro che hanno espresso il desiderio di aiutarmi in questo.

    Revisionare un manoscritto è tanto più difficile se non hai idea del materiale, ma non dovresti perderlo nessuno imprecisioni che potrebbero insinuarsi nel testo. È sorprendente che ci siano persone che accettano di modificare i testi. Christa Meadowbrook è stata l'editore di questo libro ed è stata in grado di individuare alcuni errori che tutti gli altri hanno mancato.

    Leor Zolman ha esaminato il manoscritto per tutti i campioni di codice su diversi compilatori, quindi l'ha fatto di nuovo dopo aver apportato le modifiche. Se permangono errori, ne sono responsabile, non Lheor.

    Carl Vigers e soprattutto Tim Johnson hanno scritto un breve ma utile testo per la copertina.

    John Waite, editore delle prime due edizioni di questo libro, acconsentì imprudentemente a lavorare di nuovo in tale veste. La sua assistente, Denise Michelsen, rispondeva invariabilmente con un sorriso piacevole alle mie frequenti e fastidiose osservazioni (almeno credo, anche se non l'ho mai incontrata personalmente). Julia Nakhil "ha tirato la cannuccia", doveva essere incaricata della produzione di questo libro. Per sei settimane si è alzata la notte per stare al passo con i suoi impegni senza perdere la calma. Anche John Fuller (il suo capo) e Marty Rabinowitz (il suo capo) sono stati coinvolti direttamente nel processo di produzione. I compiti ufficiali di Vanessa Moore erano di incorniciare il libro in FrameMaker e creare il testo PDF, ma ha contribuito volontariamente all'Appendice B e lo ha formattato per la stampa sulla copertina interna. Solveig Huegland ha aiutato con l'indice. Sandra Schroeder e Chuti Prasercit erano responsabili del design della copertina. Era Chuti che doveva rifare la copertina ogni volta che dicevo: "Che ne dici di mettere questa foto, ma con una striscia di un colore diverso?". Chanda Leri-Couty è completamente esausta per la commercializzazione del libro.

    Durante i mesi in cui ho lavorato al manoscritto, la serie televisiva Buffy l'ammazzavampiri mi ha aiutato a rilassarmi alla fine della giornata. Ci sono voluti molti sforzi per bandire i discorsi di Buffy dalle pagine di questo libro.

    Kathy Reed mi ha insegnato a programmare nel 1971 e sono felice che rimaniamo amici fino ad oggi. Donald French ha assunto me e Moses Legter per sviluppare tutorial C++ nel 1989 (il che mi ha reso veramente imparare C++), e nel 1991 mi ha invitato a presentarli sul computer Stratus. Poi gli studenti mi hanno incoraggiato a scrivere quella che poi è diventata la prima edizione di questo libro. Don mi ha anche presentato John White, che ha accettato di pubblicarlo.

    Mia moglie, Nancy L. Urbano, continua a incoraggiare la mia scrittura, anche dopo aver pubblicato sette libri, adattamenti su CD e una dissertazione. Ha una pazienza incredibile. Senza di lei, non sarei mai stato in grado di fare quello che ho fatto.

    Dall'inizio alla fine, il nostro cane Persefone è stato il mio compagno disinteressato. Sfortunatamente, ha partecipato alla maggior parte del progetto mentre era già nell'urna funeraria. Ci manca molto.

    Articoli correlati in alto