Innanzitutto, alcune regole pratiche:
Utilizzare std::unique_ptr
come puntatore intelligente senza spese generali. Non dovresti preoccuparti di puntatori non elaborati molto spesso. std::shared_ptr
è anche inutile nella maggior parte dei casi. Un desiderio di proprietà condivisa spesso tradisce in primo luogo una mancanza di pensiero sulla proprietà.
Utilizzare std::array
per matrici di lunghezza statica e std::vector
dinamica.
Utilizzare ampiamente algoritmi generici, in particolare:
<algorithm>
<numeric>
<iterator>
<functional>
Utilizzare auto
e decltype()
ovunque giovano alla leggibilità. In particolare, quando vuoi dichiarare una cosa, ma di un tipo che non ti interessa come un iteratore o un tipo di modello complesso, usa auto
. Quando vuoi dichiarare una cosa in termini di tipo di un'altra cosa, usa decltype()
.
Rendi le cose sicure quando puoi. Quando hai affermazioni che impongono gli invarianti su un particolare tipo di cosa, quella logica può essere centralizzata in un tipo. E questo non comporta necessariamente alcun sovraccarico di runtime. Va anche detto che i cast in stile C ( (T)x
) dovrebbero essere evitati a favore dei cast più espliciti (e ricercabili!) In stile C ++ (ad es static_cast
.).
Infine, sapere come la regola di tre:
- Distruttore
- Copia costruttore
- Operatore di assegnazione
È diventata la regola del cinque con l'aggiunta del costruttore di spostamenti e dell'operatore di assegnazione di spostamenti. Comprendi i riferimenti ai valori in generale e come evitare la copia.
C ++ è un linguaggio complesso, quindi è difficile da caratterizzare il modo migliore per utilizzare tutto di esso. Ma le pratiche del buon sviluppo del C ++ non sono cambiate sostanzialmente con il C ++ 11. Dovresti comunque preferire i contenitori gestiti dalla memoria rispetto alla gestione manuale della memoria: i puntatori intelligenti consentono di farlo in modo efficiente.
Direi che il moderno C ++ è in effetti per lo più privo di gestione manuale della memoria: il vantaggio del modello di memoria del C ++ è che è deterministico , non manuale. Deallocations prevedibili rendono le prestazioni più prevedibili.
Per quanto riguarda un compilatore, G ++ e Clang sono entrambi competitivi in termini di funzionalità C ++ 11 e stanno rapidamente recuperando le loro carenze. Non uso Visual Studio, quindi non posso parlare né a favore né contro.
Infine, una nota su std::for_each
: evitarlo in generale.
transform
, accumulate
E erase
- remove_if
sono il buon vecchio funzionali map
, fold
e filter
. Ma for_each
è più generale e quindi meno significativo: non esprime alcun intento diverso dal looping. Oltre a ciò, viene utilizzato nelle stesse situazioni di range-based for
ed è sintatticamente più pesante, anche se usato senza punti. Ritenere:
for (const auto i : container)
std::cout << i << '\n';
std::for_each(container.begin(), container.end(), [](int i) {
std::cout << i << '\n';
});
for (const auto i : container)
frobnicate(i);
std::for_each(container.begin(), container.end(), frobnicate);