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);