C++ Manuale di Stile
Il Libro Versione 2.x Errata Corrige Sommario Raccomandazioni |
Ho scritto "C++ Manuale di Stile" nel 1995. L'obiettivo era semplice: raccogliere, in un testo ragionato e non dogmatico, un insieme di raccomandazioni di codifica, utilizzate nel corso degli anni per standardizzare lo stile di vari progetti. Il desiderio di fornire una argomentazione precisa per ogni raccomandazione, se da un lato ha richiesto una discreta ricerca bibliografica, spesso al di fuori delle pubblicazioni "mainstream", dall'altro ha apportato solidita' al testo, che ancora oggi, a distanza di 15 anni, vedo talvolta consigliare. Il testo e' ancora in uso in molte aziende, e capita di ricevere email da studenti e da professionisti, interessati ad una eventuale nuova edizione o semplicemente a reperirne una copia. Nel 2005, per contratto, i diritti del libro sono tornati a me in qualita' di autore. Nel 2010 ho deciso di renderne disponibile gratuitamente una versione digitalizzata in formato DejaVu. Ho poi attivato un progetto community based per ricreare il testo originario e poterlo aggiornare e sviluppare, mantenendone la natura gratuita. Grazie all'aiuto di un piccolo gruppo di volontari il lavoro e' ormai completo. La versione Reloaded e' disponibile gratuitamente in PDF, e comprende gia' alcune modifiche ed aggiornamenti: un primo passo verso la necessaria revisione dei contenuti. Il testo contiene una breve licenza d'uso, che fondamentalmente ne consente la diffusione in ogni forma, purche' senza modifiche e senza scopo di lucro. Sentitevi quindi liberi di diffonderlo attraverso file sharing. Se avete un blog o partecipate a un social network, un semplice link a questa pagina sarebbe un ottimo modo per diffondere il libro. |
Negli anni trascorsi dalla pubblicazione, lo stile di programmazione C++ e' sicuramente cambiato. Concetti come il reference sono diventati di dominio comune. I template sono entrati a far parte dell'uso quotidiano, almeno per quanto riguarda le classi di libreria. Le eccezioni hanno modificato a fondo il modo stesso di definire il "codice robusto". Il testo, tuttavia, non e' stato aggiornato dopo il 1995. La versione Reloaded include alcuni aggiornamenti minori, ma e' necessaria una rivisitazione piu' ampia dei contenuti. La scelta degli argomenti e' ampia, la quantita' di appunti e note che ho raccolto negli anni e' altrettanto corposa. Occorre semplicemente dedicare al libro il tempo necessario. In questo momento ho deciso di rivolgere le mie energie principalmente verso un altro obiettivo (il mio lavoro sulla Physics of Software). Tuttavia non escludo di dedicare un po' di tempo al buon vecchio C++ Manuale di Stile. |
Nell'edizione cartacea (e quindi nella versione DejaVu) sono presenti alcuni errori ed imprecisioni.
Gran parte delle inesattezze riscontrate dai lettori e da una mia rilettura sono semplicemente di carattere tipografico
(spazi saltati, discendenti di alcune lettere troncati, eccetera) e sono state introdotte in fase di impaginazione. Poiché non pregiudicano la
correttezza del testo, ho preferito non riportarle in quanto segue.
Viceversa, nel libro vi sono 9 errori che vale la pena di far notare, di cui uno decisamente rilevante (vedere sotto, pagina 206).
Non si tratta in genere di errori gravi ma, in accordo allo spirito di precisione che mi ha portato a scrivere il libro, ho ritenuto giusto renderli noti ai lettori.
Nota: conto di aver riportato tutte le modifiche necessarie nella versione Reloaded. Quanto segue si applica quindi alla sola versione cartacea. Un ringraziamento va a tutti i lettori che mi hanno segnalato gli errori riscontrati. Tra questi voglio ricordare Fabio Cavanna e Roberto Romani, che per primi mi hanno fatto notare alcuni degli errori qui riportati. Come sempre, vi invito a segnalarmi ogni errore (di qualunque tipo) che vi capiti di notare nella lettura e nell'uso del libro. Pag. 16 Nella terzultima riga, "Listato 1" va cambiato in "Listato2". Pag. 28, 29, 33, 34 Le guardie di inclusione presenti nei listati (es. __BASE__) contengono un doppio underscore. Secondo lo standard ANSI/ISO, questo tipo di identificatore è riservato per l'implementazione. È quindi opportuno sostituire le guardie con identificatori con un solo underscore finale, es. BASE_. Pag. 54 La posizione delle parentesi nel secondo "if" del Listato21 é errata: if( ( ( d * e < f ) || ( g + h < i ) ) && ( a + b < c ) )dovrebbe essere: if( ( d * e < f ) || ( ( g + h < i ) && ( a + b < c ) ) )Pag. 62 Il Listato 32 dovrebbe essere: int *const s, *t ;Pag. 93 Manca una parentesi graffa chiusa nel Listato 60: else { .... } <------Pag. 118 Manca una "n" nel Listato 80, ovvero: ~io_counter() { if( --cout == 0 ) .... }dovrebbe essere: ~io_counter() { if( --count == 0 ) .... }Pag. 188 Nell'ultimo paragrafo, O(n)log(n) dovrebbe essere O(n log(n)) Pag. 206 Nel Listato 143, le righe: Bag* b = &s ; b->add( 1 ) ;Vanno modificate in: s.Bag::add( 1 ) ;Pag. 207 Nel Listato 144, la funzione hasMember dovrebbe essere inline, come spiegato nel testo soprastante il listato. Pag. 265 Nel Listato 180, il costruttore di PersonImpl deve ovviamente essere PersonImpl(), non PersonData() come erroneamente riportato. Inoltre la dichiarazione della classe PersonData all'inizio del listato è inutile. |
Introduzione
La Scelta dei Nomi
|
Raccomandazione 1 Utilizzare identificatori piu' lunghi e descrittivi per gli elementi privi di contesto; limitare la lunghezza degli identificatori quando il contesto aiuta a comprenderne il significato logico. Raccomandazione 2 Scegliete gli identificatori nel dominio del problema, non in quello della soluzione. Raccomandazione 3 Sviluppate delle convenzioni locali per i prefissi piu' comuni, come indici e numero di elementi; non lasciate pero' che il prefisso prenda il sopravvento sul corpo dell'identificatore. Raccomandazione 4 Evitare nomi che differiscono solo nel case o solo per caratteri simili, come 1 ed l ("uno" ed "elle minuscola") oppure 0 ed O ("zero" ed "o maiuscola"). In realta' sarebbe opportuno evitare totalmente l'uso dei numeri negli identificatori. Raccomandazione 5 Cercate di evitare l'uso contemporaneo di piu lingue: sceglietene una (preferibilmente l'Inglese) e restate coerenti con tale scelta durante l'intero sviluppo. Raccomandazione 6 Scegliete i nomi delle classi dal dominio del problema; il nome dovrebbe normalmente rappresentare il tipo di dato astratto, non la specifica implementazione. Raccomandazione 7 Funzioni "pure" devono avere un nome che rappresenti adeguatamente il risultato restituito. Raccomandazione 8 Funzioni con side-effects (procedure) devono avere un nome che descriva ad un giusto livello di astrazione tutti i compiti eseguiti. Usate un verbo seguito da un complemento oggetto per le funzioni non membro, ed un verbo per le funzioni membro, lasciando l'oggetto implicito. Raccomandazione 9 Scegliete gli identificatori di variabile e costante per rappresentarne l'uso, riferendovi al dominio del problema e non all'implementazione; utilizzate identificatori corti se il loro uso e' chiarito dal contesto locale, ed identificatori lunghi per variabili globali o con lifetime estesa. Raccomandazione 10 Sviluppate ed adottate una convenzione di codifica che permetta una scelta di nomi consistente tra gli sviluppatori. Raccomandazione 11 Ogni include file deve contenere un meccanismo che eviti le definizioni multiple, e possibilmente anche le inclusioni multiple. Raccomandazione 12 Utilizzare nomi di file unici in un ampio contesto: se il file contiene l'header o l'implementazione di una classe, usare il nome della classe seguito da una estensione opportuna. Raccomandazione 13 Se il vostro progetto deve essere portabile su altre piattaforme, isolate le parti dipendenti dall'hardware e dal sistema operativo e spostatele in files separati. Considerate comunque l'opportunita' di definire delle classi intermedie per isolare l'applicazione dal sistema. Raccomandazione 14 Limitate l'uso di funzionalita' specifiche del compilatore; spostate sempre le parti di codice dipendenti dal compilatore in files separati. Raccomandazione 15 Se l'accesso ad una classe all'interno di un header file avviene solo tramite reference o puntatore, non includete l'header di tale classe, ma dichiarate semplicemente l'identificatore della classe nell'header stesso. Raccomandazione 16 Se utilizzate gli header precompilati, includete gli header di libreria per primi, poi gli header piu' stabili, ed infine quelli piu' frequentemente modificati; usate il meccanismo del vostro compilatore per fermare la precompilazione dopo gli header di sistema o dopo quelli piu' stabili. Raccomandazione 17 Racchiudete i nomi degli header di libreria tra <> e degli header privati tra "". Raccomandazione 18 Non specificate le directory nei file header inclusi: utilizzate il supporto del compilatore per specificare le directory da utilizzare. Raccomandazione 19 Utilizzate una diversa directory per i moduli oggetto di ogni progetto. Raccomandazione 20 Utilizzate linee vuote per separare elementi logicamente distinti, anche all'interno della singola funzione o blocco applicativo. Cercate di limitare gli elementi decorativi nei commenti, che deviano l'attenzione di chi legge. Raccomandazione 21 Indentate gli statement subordinati sotto agli statement da cui dipendono. Raccomandazione 22 Definite uno standard di indentazione che sia rispettato da ogni membro del team di sviluppo. Raccomandazione 23 Definite uno standard interno sulla lunghezza e l'uso del tab che sia rispettato da tutti i programmatori del team. Raccomandazione 24 Definite uno standard per la sequenza delle dichiarazioni in un file header, ed aderitevi strettamente ogni volta che sia possibile. Raccomandazione 25 Il file di implementazione deve definire ogni elemento nell'esatto ordine di dichiarazione del file header associato. Raccomandazione 26 Usare una spaziatura uniforme tra gli operatori e gli operandi; vi sono sicuramente eccezioni, ma anche su queste cercate di essere consistenti con un vostro standard di layout. Raccomandazione 27 Utilizzate le parentesi solo quando sono necessarie ai fini semantici, o per chiarire la priorita' e/o l'associativita' degli operatori. Raccomandazione 28 Spezzate le espressioni troppo complesse, in particolar modo le espressioni booleane, assegnandone una sottoespressione significativa ad una variabile locale. Raccomandazione 29 Utilizzate sempre le parentesi per chiarire il significato di espressioni che coinvolgono operatori bit-wise ed altri operatori. Questo e' valido anche quando gli operatori bit-wise sono overloaded, come nel caso degli operatori << e >> per l'I/O su stream. Raccomandazione 30 Specificare il nome dei parametri formali sia nel file header che nel file di implementazione, ed utilizzare gli stessi identificatori in entrambi i contesti. Raccomandazione 31 Se un parametro formale non e' utilizzato, racchiudere il suo nome in un commento nel file implementazione. Raccomandazione 32 Evitare l'allineamento nelle dichiarazioni di variabili: utilizzare semplicemente una spaziatura standard. Raccomandazione 33 Dichiarare una sola variabile in ogni statement di dichiarazione. Raccomandazione 34 Variabili di tipo puntatore (o di tipo riferimento) vanno dichiarate giustapponendo il simbolo * (o il simbolo &) al tipo dell'oggetto puntato (o referenziato), ovvero come nell'esempio che segue: int* x ; Raccomandazione 35 Se utilizzate tipi complessi, ad esempio puntatori a funzione, dichiarate un tipo apposito con typedef. Raccomandazione 36 Utilizzate sempre la struttura di controllo che meglio esprime le azioni che intendete compiere ad un livello piu' astratto. Raccomandazione 37 Preferire il break o un flag al return per uscire dai loop. Raccomandazione 38 Se il body di uno statement e' vuoto, posizionate il ';' o un blocco vuoto su una riga separata, ed annotatelo con un commento. Raccomandazione 39 Nei cicli for, utilizzate un limite inferiore inclusivo ed un limite superiore esclusivo. Raccomandazione 40 Usare il nesting con discernimento: talvolta e' possibile linearizzare la struttura del codice con un impatto trascurabile sulle prestazioni. Raccomandazione 41 Ogni clausola di uno statement switch va terminata con break o con return, salvo i casi di fall-through intenzionale che devono sempre essere commentati. Raccomandazione 42 Introdurre sempre una clausola default negli statement switch; se il controllo non deve mai raggiungere tale clausola, inserire una asserzione falsa come corpo, in modo che ogni violazione delle assunzioni fatte venga segnalata a run-time. Raccomandazione 43 Strutturate la dichiarazione di una classe ordinando le sezioni di accessibilita' come pubblica/protetta/privata, seguite da classi, funzioni, operatori friend. Raccomandazione 44 All'interno di ogni sezione, seguite un layout il piu' vicino possibile a quello di un file header, con le dovute differenze per i membri statici. Raccomandazione 45 La definizione delle funzioni inline non va inserita all'interno della dichiarazione della classe, ma al di fuori di essa. Raccomandazione 46 Nei commenti, cercate di spiegare le vostre intenzioni, non come le state realizzando. Preferite i commenti introduttivi a quelli esplicativi, che spesso si possono evitare scrivendo codice piu' chiaro. Raccomandazione 47 Indentare i commenti allo stesso livello del codice a cui si riferiscono. Raccomandazione 48 Evitare di inserire esplicitamente valori numerici nel codice: definire invece delle opportune costanti. Raccomandazione 49 Non utilizzare #define per definire le costanti, ma const o enum. Raccomandazione 50 Usare enum per raggruppare costanti omogenee; utilizzare const per dichiarare costanti eterogenee. Raccomandazione 51 Se una o piu' costanti sono utilizzate solo all'interno di una classe, o come parametri per le funzioni membro di una classe, le costanti vanno definite internamente alla classe, e dotate del giusto grado di visibilita' (private, protected o public) a seconda dell'impiego che possono avere. Raccomandazione 52 Utilizzare sempre il tipo piu' opportuno per ogni variabile; non abusare dei tipi int o float: talvolta unsigned puo' essere piu' indicato. Raccomandazione 53 Non utilizzare i tipi predefiniti esplicitamente qualora sia possibile (e significativo) nascondere l'implementazione definendo un opportuno tipo con typedef od enum. Raccomandazione 54 Non dichiarate diverse variabili logicamente correlate se definendo una opportuna classe e' possibile riunirle in un'unica struttura. Raccomandazione 55 Dichiarare le variabili in modo da avere vita e scope minimi, ovvero all'ultimo istante possibile, e con il massimo grado di annidamento possibile. Raccomandazione 56 Inizializzare le variabili al momento della dichiarazione ogni volta che e' possibile; altrimenti, considerare la possibilita' di astrarre parte del codice in una funzione. Raccomandazione 57 All'interno dei blocchi, non dichiarare variabili aventi lo stesso identificatore di una variabile visibile nello stesso scope. Raccomandazione 58 Considerate sempre le variabili locali static come candidati a divenire membri di una opportuna classe: se si trovano all'interno di funzioni membro, possono divenire membri della stessa classe; se si trovano in funzioni non-membro, dovra' essere introdotta una nuova classe, se corrisponde ad una astrazione significativa. Raccomandazione 59 Non utilizzare una variabile dichiarata in uno statement di selezione o di iterazione, al di fuori dello statement stesso: il codice non rispettera' lo standard ISO C++. Raccomandazione 60 Minimizzare l'uso delle variabili globali. Raccomandazione 61 Se e' necessario introdurre un oggetto globale, costruire una opportuna classe che gestisca l'elemento come una risorsa, eventualmente con gli opportuni costrutti di locking. Raccomandazione 62 Non dichiarare funzioni private come virtual. Raccomandazione 63 Se si modifica la visibilita' di una funzione in una classe derivata, motivare le ragioni della modifica con un opportuno commento. Raccomandazione 64 Non eccedere nel numero di costruttori: introducete solo quelli realmente necessari. Attenzione ai costruttori con un solo parametro, che sono a tutti gli effetti operatori di conversione. Raccomandazione 65 Non chiamare funzioni virtuali all'interno del costruttore: non verranno in ogni caso legate dinamicamente, ma sempre legate staticamente. Se e' necessario chiamarle, introducete comunque un commento esplicativo. Raccomandazione 66 Parametri di tipo puntatore o reference nei costruttori dovrebbero sempre essere const, in modo tale che il costruttore non modifichi i suoi parametri. Raccomandazione 67 Ogni classe avente funzioni virtuali, o utilizzata come classe base in una gerarchia di derivazione, deve dichiarare il distruttore come virtual. Negli altri casi, commentate opportunamente l'header della classe, cosi' che l'introduzione di classi derivate coincida con la modifica del distruttore in virtual. Raccomandazione 68 Nei costruttori di oggetti composti da piu' parti, inizializzate i sotto-oggetti con la tecnica <whole> : <part>, non tramite assegnazione. L'assegnazione e' di norma preferibile per i sottocomponenti di tipo base. Raccomandazione 69 Una classe che abbia membri allocati dinamicamente deve definire un opportuno costruttore di copia. Raccomandazione 70 Una classe che abbia membri allocati dinamicamente deve definire un opportuno distruttore. Raccomandazione 71 Evitare, se possibile, l'uso di oggetti globali all'interno dei costruttori. Se e' necessario, utilizzate la tecnica di Schwarz per garantire il corretto ordine di inizializzazione. Raccomandazione 72 I costruttori ed i distruttori non dovrebbero essere inline, tranne per classi base molto semplici, dalle quali non di derivera' in futuro, o nei casi in cui siano vuoti. Raccomandazione 73 Non definire dati pubblici o protetti: tutti i dati devono essere privati. Raccomandazione 74 Non definire metodi di get/set pubblici, e limitarsi il piu' possibile anche nel caso di metodi protected: cercate di identificare piu' chiaramente le responsabilita' ed i compiti della classe, anziche' esporne i dati. Se definite metodi di get/set protected, usate astrazioni a livello logico. Raccomandazione 75 Limitare l'uso di struct all'interfacciamento con codice C; utilizzare le classi in tutti gli altri casi. Raccomandazione 76 Funzioni od operatori pubblici che restituiscano puntatori o reference a campi di una classe devono restituirli come puntatori/reference const. Raccomandazione 77 Funzioni o operatori pubblici non devono restituire il valore di un membro di tipo puntatore o reference, se non sotto forma di puntatore const o reference const. Raccomandazione 78 Non definite operatori di conversione pubblici che restituiscano puntatori/reference a membri o membri puntatore/reference: utilizzate invece funzioni membro dal nome esplicativo, che ricordino al programmatore la sua responsabilita' nell'utilizzo del puntatore/reference ottenuto, che deve comunque essere const. Raccomandazione 79 In ogni classe, limitate il numero di chiamate a funzioni virtuali dichiarate nella classe stessa. Raccomandazione 80 Per ogni funzione virtuale dichiarata in una classe e richiamata nel codice della classe stessa, documentare adeguatamente nel file header della classe ogni contesto di chiamata. Specificate chiaramente quali vincoli sul contesto verranno rispettati in future versioni della classe (e rispettateli!) e quali possono essere variati senza preavviso. Raccomandazione 81 Nelle gerarchie di derivazione con ereditarieta' singola, l'uso di inherited :: per qualificare la classe genitore puo' semplificare significativamente la manutenzione della gerarchia stessa. Raccomandazione 82 L'uso della qualificazione esplicita con :: dovrebbe essere limitato all'interno delle classi base (per ottenere l'early binding con il metodo della classe stessa) o nelle classi derivate (per richiamare i metodi delle classi base). Non dovrebbe essere usato al di fuori di esse, dove oggetti delle classi vengono usati. Raccomandazione 83 Funzioni che non modificano lo stato dell'oggetto vanno dichiarate const; cio' andrebbe fatto sin dalla fase di definizione dell'interfaccia della classe. Raccomandazione 84 Se possibile, non modificate oggetti globali o sotto-oggetti accessibili tramite puntatori all'interno di funzioni membro const, e non eseguite input-output all'interno di esse. Se dovete farlo, commentate adeguatamente il codice, e magari anche la dichiarazione della funzione. Raccomandazione 85 Dovendo modificare membri dato all'interno di un oggetto, ammesso che cio' sia concettualmente corretto, dichiarate i dati come mutable; in alternativa, usate const_cast all'interno della funzione membro che deve modificare i dati, od un cast esplicito se const_cast non e' disponibile. Raccomandazione 86 Se un operatore viene ridefinito, la sua semantica dovrebbe risultare il piu' possibile naturale; gli operatori della stessa famiglia logica dovrebbero essere a loro volta ridefiniti in modo che vengano preservate le usuali equivalenze semantiche. Raccomandazione 87 Non ridefinite gli operatori || ed && se non e' veramente necessario; se dovete farlo, aggiungete sempre una linea di commento nel file header, richiamando esplicitamente la mancanza di short-circuit nella valutazione. Raccomandazione 88 Una classe che abbia membri allocati dinamicamente deve definire un opportuno operatore di assegnazione. Raccomandazione 89 Un operatore di assegnazione che esegua operazioni distruttive sul suo operando di sinistra, deve per prima cosa verificare la non-identita' dei due operandi. Raccomandazione 90 Il parametro di destra di un operatore di assegnazione dovrebbe essere const; nei rari casi in cui cio' non e' possibile, commentare adeguatamente l'header della classe. Raccomandazione 91 Il risultato di un operatore di assegnazione dovrebbe essere di tipo void oppure un reference const alla classe per la quale l'operatore e' definito. Raccomandazione 92 Le funzioni friend non devono accedere ai dati privati della classe; se necessario, definire delle funzioni inline private di Get/Set, per accedere ai dati membro. Raccomandazione 93 Legge di Demeter (formulazione "per oggetti") Un metodo M della classe C dovrebbe richiamare solo metodi della classe C, metodi delle sottoparti immediate di C, metodi degli argomenti di M, metodi degli oggetti creati internamente ad M o metodi di oggetti globali. Raccomandazione 94 Non usate i reference per creare degli alias; se dovete creare alias, utilizzate i puntatori. Raccomandazione 95 Per ottenere il passaggio per riferimento, utilizzate sempre i tipi reference e non i puntatori. Se il fine del passaggio per riferimento e' di evitare la copia di un oggetto di grosse dimensioni, che non verra' comunque modificato, dichiarare il parametro come un reference const. Raccomandazione 96 Limitare l'uso dell'aritmetica sui puntatori: in molte occasioni, l'uso diretto degli array generera' codice piu' leggibile, sicuro, ed altrettanto efficiente. Raccomandazione 97 Utilizzate una classe Array basata su template anziche' gli array C-style. Raccomandazione 98 Utilizzate sempre delete[] per distruggere array di oggetti, e delete per distruggere i singoli oggetti. Raccomandazione 99 Dopo la chiamata a delete o delete[], assegnate il valore NULL alla variabile nel caso si tratti di un membro di una classe o di una variabile globale. Lo stesso vale se si tratta di una variabile locale il cui scope si estende per molte righe dopo la sua distruzione. Raccomandazione 100 Minimizzate l'uso di puntatori a puntatore. Raccomandazione 101 Evitate l'uso di parametri booleani; definite invece un apposito tipo enumerato per le diverse opzioni. Il tipo puo' essere definito internamente ad una classe per evitare la saturazione dello spazio degli enumerati Raccomandazione 102 Non restituite puntatori ad elementi statici o globali come risultato delle funzioni. Raccomandazione 103 Non restituite, come risultati di funzione, puntatori a memoria allocata all'interno della funzione, e che debba essere deallocata dal chiamante. Raccomandazione 104 Se una funzione deve restituire dati creati dinamicamente, considerate l'opportunita' di creare una classe wrapper che gestisca l'allocazione/deallocazione dei dati. Raccomandazione 105 Non restituite valori eterogenei come risultato delle vostre funzioni; se necessario, utilizzate un ulteriore parametro per codici di errore, o generate una eccezione a run-time. Raccomandazione 106 Inserite asserzioni nel codice per verificare precondizioni, postcondizioni ed invarianti. Le asserzioni vanno utilizzate per trovare errori di codifica, non per gestire errori run-time dovuti all'interazione con l'ambiente. Raccomandazione 107 Non inserite codice che genera side-effect all'interno delle asserzioni: tale codice non verra' compilato come parte della release finale. Raccomandazione 108 Se la condizione verificata all'interno di una asserzione non e' di immediata comprensione, commentatela adeguatamente. Raccomandazione 109 Evitate di scrivere funzioni troppo lunghe; se vi sono importanti ragioni per non suddividere una funzione lunga in sottofunzioni, documentate le motivazioni con un opportuno commento. Raccomandazione 110 Utilizzare le funzioni inline anziche' definire macro-funzioni con #define. Raccomandazione 111 Utilizzate le funzioni inline solo se vi sono concreti motivi: il fatto che una funzione sia breve non giustifica di per se' l'espansione in linea. Raccomandazione 112 Utilizzare le funzioni inline solo quando l'overhead di chiamata e' significativo rispetto al tempo di esecuzione del corpo della funzione stessa. Funzioni di forwarding o funzioni protected di accesso ai membri dato sono normalmente buoni candidati all'espansione in linea. Raccomandazione 113 Tutte le versioni overloaded di una stessa funzione dovrebbero avere la stessa semantica, perlomeno ad un alto ma riconoscibile livello di astrazione. Raccomandazione 114 Non utilizzare i parametri di default per simulare l'overloading in una sola funzione: una funzione dovrebbe svolgere un unico compito. Raccomandazione 115 Parametri di default devono essere forniti solo quando la maggior parte delle chiamate sfruttera' effettivamente tali parametri. Raccomandazione 116 Limitare il passaggio per valore di oggetti di grandi dimensioni, e la restituzione per valore di oggetti di grandi dimensioni. Raccomandazione 117 Evitare codice che dipende dalla lifetime di oggetti temporanei; se cio' e' necessario per ragioni di efficienza, commentare la porzione di codice in modo adeguato. Raccomandazione 118 Se lavorate con oggetti di grande dimensione, non utilizzare operatori postfissi; se create una classe con oggetti di grandi dimensione, non definite operatori postfissi. Raccomandazione 119 Utilizzate la derivazione pubblica o protetta solo se state effettivamente modellando una relazione del tipo e'-un. Negli altri casi, utilizzate l'ereditarieta' privata o il contenimento. Raccomandazione 120 Non restiruire mai un puntatore ad una classe base attraverso una funzione pubblica o protetta di una classe derivata con ereditarieta' privata. Raccomandazione 121 Se una funzione di una classe derivata come private chiama una funzione virtuale della classe base, e' necessario legarla staticamente alla funzione della classe base, evitando la risoluzione dinamica della chiamata. Raccomandazione 122 Non ridefinire funzioni virtuali di una classe base non accessibile. Raccomandazione 123 La derivazione privata da una classe base che chiama al suo interno funzioni virtuali dovrebbe essere sostituita dal contenimento diretto. Raccomandazione 124 Non ridefinite le funzioni non virtuali delle classi basi in classi derivate public o protected (ereditarieta' di interfaccia); nel caso occorra farlo, verificate che non sia comunque piu' corretto derivare come private (ereditarieta' di implementazione) Raccomandazione 125 Se utilizzate il binding statico per eliminare l'ambiguita' dovuta all'ereditarieta' multipla, commentate adeguatamente il codice per prevenire problemi di manutenzione; considerate comunque l'alternativa di utilizzare i puntatori a funzioni membro. Raccomandazione 126 L'ereditarieta' fork-join accessibile deve sempre essere virtuale. Raccomandazione 127 L'ereditarieta' fork-join non accessibile non deve mai essere virtuale. Raccomandazione 128 Quando e' possibile, utilizzate l'ereditarieta' virtuale ogni volta che derivate in modo pubblico o protetto. Raccomandazione 129 L'ereditarieta' privata dovrebbe sempre essere non-virtual. Raccomandazione 130 Attenzione all'overloading di funzioni parametrizzate e non parametrizzate nei template, che puo' impedire l'istanziazione con alcuni parametri. Preferibilmente, spostate le funzioni non parametriche in una classe base. Raccomandazione 131 Dati e funzioni membro di un template che siano indipendenti dai parametri del template possono essere spostate in una classe base da cui il template e' derivato. Raccomandazione 132 Non usare un cast, di nessun tipo, quando e' possible utilizzare l'operatore di qualificazione esplicita :: Raccomandazione 133 Se e' realmente necessario convertire un puntatore a classe base ad un puntatore a classe derivata, o in generale invertire una conversione implicita, utilizzate l'operatore static_cast e non un cast C-style. Se vi e' la possibilita' che la conversione fallisca, utilizzate dynamic_cast. Raccomandazione 134 Nei rari casi in cui e' realmente necessario convertire oggetti const in oggetti non-const, utilizzate l'operatore const_cast. Raccomandazione 135 Nei rari casi in cui sia realmente necessario eseguire un cast che puo' fallire a run-time, utilizzate l'operatore dynamic_cast, non il cast C-style. Raccomandazione 136 Se e' realmente necessario eseguire un cast tra tipi scorrelati, utilizzate l'operatore reinterpret_cast, non il cast C-style. Raccomandazione 137 In caso di possibile ambiguita', utilizzare un cast esplicito anziche' appoggiarsi al meccanismo di cast implicito del linguaggio. Raccomandazione 138 Non richiedere mai un cast implicito o esplicito da un array di oggetti di classe derivata ad un array di oggetti di classe base. Raccomandazione 139 Utilizzare gli stream di I/O anziche' printf ovunque sia possibile. Raccomandazione 140 Non assumete che il vostro codice sia portabile ad un altra piattaforma o semplicemente ad un altro compilatore solo perche' funziona con il vostro sistema e compilatore. Raccomandazione 141 Compilate sempre il vostro codice con il massimo numero di warning abilitati; eliminate i warning rimuovendone la causa, non zittendo il compilatore. Evitate l'uso dei #pragma. Raccomandazione 142 Non fate assunzioni arbitrarie sulle grandezze dei tipi, specialmente sulle grandezze relative di short, int, long, e puntatori. Usate i tipi standard per contenere le differenze tra puntatori. Se e' necessario fare riferimento alla dimensione di un tipo base, definite un apposito tipo utilizzando la compilazione condizionale. Raccomandazione 143 Non assumete un particolare layout di memorizzazione per i tipi base. Raccomandazione 144 Se usate i bit-field, non trattate mai una sequenza di campi come una singola unita'. Raccomandazione 145 Non fate assunzioni sul layout in memoria degli oggetti. Raccomandazione 146 Non comparate puntatori a tipi diversi. Gli operatori <, <=, >, >= sono definiti solo per puntatori che puntano all'interno dello stesso array, o al primo elemento dopo la fine dell'array stesso. Raccomandazione 147 Non assumete che la chiamata di funzione comporti la valutazione degli argomenti in un ordine particolare. Raccomandazione 148 Gli operandi di un operatore con side-effect non devono avere altre occorrenze nella stessa espressione. Raccomandazione 149 Non utilizzate l'ereditarieta' per modellare relazioni del tipo tutto-parti, che vanno modellate con il contenimento. Raccomandazione 150 Quando possibile, utilizzate la composizione diretta per i sotto-oggetti, non la composizione tramite puntatori. Raccomandazione 151 Non utilizzate schemi di type-checking dinamico per ottenere genericita': preferite invece l'uso dei template. Raccomandazione 152 Se i tempi di ricompilazione dopo la modifica di parti private delle classi sono troppo lunghi, minimizzate l'accoppiamento tra le implementazioni delle classi usando una tecnica di isolamento. |