Primeiro, algumas regras práticas:
Use std::unique_ptr
como 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::array
para matrizes de comprimento estático e std::vector
para dinâmico.
Use algoritmos genéricos extensivamente, em particular:
<algorithm>
<numeric>
<iterator>
<functional>
Use auto
e 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
, accumulate
E erase
- remove_if
são bom e velho funcional map
, fold
e 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 for
e é 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);