Innanzitutto, alcune regole pratiche:
-
Usa std::unique_ptr
come puntatore intelligente senza overhead. Non dovresti aver bisogno di preoccuparti dei puntatori grezzi tutto questo spesso. std::shared_ptr
è ugualmente inutile nella maggior parte dei casi. Un desiderio di proprietà condivisa spesso tradisce una mancanza di pensiero sulla proprietà in primo luogo.
-
Utilizza std::array
per array di lunghezza statica e std::vector
per dinamico.
-
Utilizza estensivamente algoritmi generici, in particolare:
-
<algorithm>
-
<numeric>
-
<iterator>
-
<functional>
-
Utilizza auto
e decltype()
ovunque siano a vantaggio della 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 al tipo quando puoi. Quando si hanno asserzioni che impongono invarianti su un particolare tipo di cosa, tale logica può essere centralizzata in un tipo. E questo non fa necessariamente per qualsiasi 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 esempio static_cast
).
-
Infine, conosci la regola del tre:
- Destructor
- Copia costruttore
- Operatore di assegnazione
È diventata la regola del cinque con l'aggiunta del costruttore di movimento e dell'operatore di spostamento. E capire i riferimenti rvalue in generale e come evitare di copiare.
C ++ è un linguaggio complesso, quindi è difficile caratterizzare il modo migliore per utilizzare tutti di esso. Ma le pratiche di un buon sviluppo del C ++ non sono cambiate fondamentalmente con C ++ 11. Dovresti comunque preferire i contenitori gestiti tramite memoria rispetto alla gestione manuale della memoria: i puntatori intelligenti semplificano l'esecuzione in modo efficiente.
Direi che il C ++ moderno è per lo più privo di gestione manuale della memoria: il vantaggio del modello di memoria di C ++ è che è deterministico , non che sia manuale. Le deallocazioni prevedibili offrono prestazioni più prevedibili.
Come per un compilatore, G ++ e Clang sono entrambi competitivi in termini di funzionalità di C ++ 11 e recuperano rapidamente le loro carenze. Non utilizzo Visual Studio, quindi non posso parlare né a favore né contro di esso.
Infine, una nota su std::for_each
: evitali in generale.
transform
, accumulate
e erase
- remove_if
sono buoni vecchi funzionali map
, fold
e filter
. Ma for_each
è più generale, e quindi meno significativo: non esprime alcun intento diverso dal ciclo. Oltre a ciò, viene utilizzato nelle stesse situazioni di for
basato su intervallo ed è sintatticamente più pesante, anche se utilizzato senza punto. Prendere in considerazione:
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);