Estou programando em C ++ há algum tempo, mas principalmente as coisas estão centradas nos recursos de baixo nível do C ++. Com isso, quero dizer principalmente trabalhando com ponteiros e matrizes brutas. Eu acho que esse comportamento é conhecido como usar C ++ como C com classes. Apesar disso, eu apenas tentei C recentemente pela primeira vez. Fiquei agradavelmente surpreso com o fato de linguagens como C # e Java esconderem esses detalhes em convenientes classes de bibliotecas padrão, como dicionários e listas.
Estou ciente de que a biblioteca padrão do C ++ também possui muitos contêineres, como vetores, mapas e seqüências de caracteres, e o C ++ 11 só contribui para isso, tendo std :: array e loops à distância.
Como melhor aprendo a usar esses recursos da linguagem moderna e quais são adequados para quais momentos? É correto que a engenharia de software em C ++ atualmente esteja livre de gerenciamento manual de memória?
Por fim, qual compilador devo usar para aproveitar ao máximo o novo padrão? O Visual Studio possui excelentes ferramentas de depuração, mas até o VS2012 parece ter um suporte terrível ao C ++ 11.
g++ -std=c++11
Respostas:
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 estd::vector
para dinâmico.Use algoritmos genéricos extensivamente, em particular:
<algorithm>
<numeric>
<iterator>
<functional>
Use
auto
edecltype()
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, useauto
. Quando você quiser declarar uma coisa em termos do tipo de outra coisa, usedecltype()
.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:
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
Eerase
-remove_if
são bom e velho funcionalmap
,fold
efilter
. Masfor_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 alcancefor
e é sintaticamente mais pesado, mesmo quando usado sem pontos. Considerar:fonte
std::for_each
eu esperava que o intervalo baseado em loop fosse um substituto melhor que o normalfor
.std::for_each
, não com base em intervalo . Eu o removi para evitar confusão.std::for_each()
. Quando você tem lambda, certamente é melhor que umfor
loop tradicional . Com umfor
loop baseado em intervalo que pode não ser o caso, mas você não escreveu "for
loop baseado em intervalo ".for
loop" inclui "for
loop baseado em faixa ". Eu editei com mais explicações e um exemplo para esclarecer, obrigado.Como ponto de partida:
char*
para strings. Usestd::string
oustd::wstring
observe o seu código ficar mais curto, mais legível e mais seguro[ ]
) e usestd::vector
ou alguma outra classe de contêiner apropriada. O bomstd::vector
é que ele conhece seu próprio comprimento, limpa seu conteúdo quando sai do escopo, é fácil de repetir e fica maior quando você adiciona mais itens. Mas existem outras coleções que podem funcionar ainda melhor para as suas circunstâncias.std::unique_ptr
- e aprendastd::move
quase imediatamente. Uma vez que este pode resultar em alguns objetos noncopyable, preguiça pode ocasionalmente enviar-lhe direçãostd::shared_ptr
- e você pode ter alguns casos de uso reais parastd::shared_ptr
bemauto
ao declarar iteradores e tipos que dependem de declarações anteriores (por exemplo, anteriormente você declarou um vetor de algo, agora você está declarando algo, useauto
)for_each
sobre um "raw for" sempre que puder, pois isso poupa outros de lerem seu loop com cuidado para concluir que você está de fato repetindo toda a coleção etc. Se o seu compilador suportar "range for", use-o novamentefor_each
. Saiba chamadas algoritmo triviais comoiota
,generate
,accumulate
,find_if
e assim por diante.Não fique muito preocupado com o compilador a usar. A falta "terrível e terrível" de suporte ao C ++ 11 no VS2012 é que não há modelos variados (sim, certo, você estava prestes a usar modelos variados) e o
{}
inicializador não existe. Também quero isso, mas dificilmente vou parar de usar uma ferramenta de desenvolvimento útil sobre ele.A segunda coisa a fazer, depois de abraçar
std::
, é começar a pensar em RAII. Sempre que você tiverEntão, o que você tem é um construtor, várias funções de membro e um destruidor. Escreva uma classe que cuide disso para você. Você pode nem precisar escrever o ctor e o dtor. Colocar uma
shared_ptr
variável como membro de uma classe é um exemplo de RAII - você não escreve código de gerenciamento de memória, mas quando sua instância fica fora do escopo, as coisas certas acontecem. Expanda esse pensamento para cobrir coisas como fechar arquivos, liberar identificadores, bloqueios, etc.Se você estiver realmente confiante, escolha a
printf
favorcout
, livre-se das macros (#define
coisas) e comece a aprender alguns "idiomas avançados", como o PIMPL. Eu tenho um curso completo sobre isso na Pluralsight, que você provavelmente pode assistir usando o teste gratuito.fonte
Pela programação. A experiência é a melhor maneira de aprender.
O C ++ 11 possui muitos novos recursos (automático, rvalor, novos indicadores inteligentes - apenas para citar alguns). O melhor começo é começar a usá-los e ler sobre eles sempre que puder e sempre que encontrar um artigo interessante.
Isso depende do que você precisa fazer. A maioria dos aplicativos pode usar ponteiros inteligentes e esquecer o gerenciamento de memória. Ainda existem aplicativos que não conseguem escapar tão facilmente (por exemplo, se eles precisam de um novo posicionamento ou de um alocador de memória personalizado por qualquer motivo).
Se você precisar usar o Qt, precisará usar as regras para gerenciamento de memória.
Tudo o que você tem em mãos que suporta o padrão mais recente:
mas nenhum compilador suporta todos os recursos.
fonte
Minha universidade ainda está usando C ++ para o ensino. Programei com C ++ por 5 anos e agora sou estudante de pós-graduação. Claro, agora estou usando muito Java, Ruby etc. Eu realmente recomendo que você não se apresse com esses recursos em linguagens como Java. Na minha experiência e opinião, após os recursos de baixo nível do C ++. Você deve examinar tópicos como programação genérica com C / C ++, como criar classe de modelo, funções de modelo, substituição de operador, métodos virtuais, ponteiros inteligentes. Para a Parte de Design Orientado a Objetos, há muitos recursos que o C ++ possui e o Java não, como a herança múltipla. A herança é poderosa, mas perigosa também. O nível de implementação do design orientado a objetos em C ++ também é um bom tópico. A comunicação entre processos, encadeamentos, também é importante em C ++.
Para o compilador e depurador. Eu sei que o visual studio é incrível. Mas eu realmente recomendo que você aprenda GDB, Valgrind e Make still, e seja bom nessas ferramentas. A Microsoft é incrível, mas fez muitas coisas para você. Como estudante, você realmente precisa aprender as coisas que a Microsoft fez também com você. Para o compilador, o G ++ é bom no GNU.
Afinal, depois de tantos anos, eu realmente sinto que as coisas mais importantes são os recursos de baixo nível, como o array bruto. O vetor é realmente apenas uma matriz dinâmica. Estas são as minhas recomendações, algo talvez muito subjetivo, basta pegar o que você acha certo.
fonte