Primeiro, algumas regras práticas:
Use std::unique_ptrcomo um ponteiro inteligente sem sobrecarga. Você não precisa se preocupar com ponteiros brutos com tanta frequência. std::shared_ptré igualmente desnecessário na maioria dos casos. Um desejo de propriedade compartilhada muitas vezes denota uma falta de pensamento sobre propriedade em primeiro lugar.
Use std::arraypara matrizes de comprimento estático e std::vectorpara dinâmico.
Use algoritmos genéricos extensivamente, em particular:
<algorithm>
<numeric>
<iterator>
<functional>
Use autoe decltype()onde quer que eles beneficiem da legibilidade. Em particular, quando quiser declarar algo, mas de um tipo com o qual você não se importa, como um iterador ou um tipo de modelo complexo, use auto. Quando você quiser declarar uma coisa em termos do tipo de outra coisa, use decltype().
Torne as coisas seguras quando você puder. Quando você tem afirmações que impõem invariantes a um tipo específico de coisa, essa lógica pode ser centralizada em um tipo. E isso não significa necessariamente sobrecarga de tempo de execução. Também não é necessário dizer que os lançamentos no estilo C ( (T)x) devem ser evitados em favor dos lançamentos no estilo C ++ mais explícitos (e pesquisáveis!) (Por exemplo, static_cast).
Por fim, saiba como a regra dos três:
- Destruidor
- Copiar construtor
- Operador de atribuição
Tornou-se a regra dos cinco com a adição do construtor de movimentação e do operador de atribuição de movimentação. E entenda as referências do rvalue em geral e como evitar a cópia.
Como o C ++ é uma linguagem complexa, é difícil caracterizar a melhor forma de usar tudo isso. Mas as práticas de bom desenvolvimento de C ++ não mudaram fundamentalmente com o C ++ 11. Você ainda deve preferir os contêineres gerenciados pela memória ao invés do gerenciamento manual da memória - indicadores inteligentes facilitam isso com eficiência.
Eu diria que o C ++ moderno é realmente livre de gerenciamento manual de memória - a vantagem do modelo de memória do C ++ é que ele é determinístico , não manual. As distribuições previsíveis proporcionam um desempenho mais previsível.
Quanto a um compilador, o G ++ e o Clang são competitivos em termos de recursos do C ++ 11 e rapidamente recuperam suas deficiências. Como não uso o Visual Studio, não posso falar a favor nem contra.
Finalmente, uma observação sobre std::for_each: evite-o em geral.
transform, accumulateE erase- remove_ifsão bom e velho funcional map, folde filter. Mas for_eaché mais geral e, portanto, menos significativo - não expressa nenhuma intenção além de repetir. Além disso, é usado nas mesmas situações que com base em alcance fore é sintaticamente mais pesado, mesmo quando usado sem pontos. Considerar:
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);