Como fazer a mudança para o C ++ 11?

35

Eu tenho programado em C ++ há algum tempo, mas principalmente coisas centradas em torno dos recursos de baixo nível do C ++. Por isso quero dizer principalmente trabalhando com ponteiros e matrizes cruas. Eu acho que esse comportamento é conhecido como usando C ++ como C com classes. Apesar disso, eu só tentei C recentemente pela primeira vez. Fiquei agradavelmente surpreso como linguagens como C # e Java escondem esses detalhes em convenientes classes de bibliotecas padrão, como Dicionários e Listas.

Estou ciente de que a biblioteca padrão C ++ possui muitos contêineres, como vetores, mapas e cadeias de caracteres, e o C ++ 11 só adiciona isso ao ter loops std :: array e ranged.

Como melhor aprender a usar esses recursos de linguagem modernos e quais são adequados para quais momentos? É correto que a engenharia de software em C ++ atualmente esteja livre de gerenciamento de memória manual?

Por fim, qual compilador devo usar para aproveitar ao máximo o novo padrão? O Visual Studio tem excelentes ferramentas de depuração, mas mesmo o VS2012 parece ter um péssimo suporte para o C ++ 11.

    
por Overv 23.10.2012 / 00:37
fonte

4 respostas

50

Primeiro, algumas regras básicas:

  • Use std::unique_ptr como um ponteiro inteligente sem sobrecarga. Você não precisa se preocupar com os indicadores brutos com tanta frequência. std::shared_ptr é igualmente desnecessário na maioria dos casos. Um desejo de propriedade compartilhada geralmente revela 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 se beneficiem da legibilidade. Em particular, quando você deseja declarar algo, mas de um tipo com o qual 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 ao digitar quando possível. Quando você tem afirmações que impõem invariantes em um tipo particular de coisa, essa lógica pode ser centralizada em um tipo. E isso não significa necessariamente qualquer sobrecarga de tempo de execução. Também deve ser dito que os moldes em estilo C ( (T)x ) devem ser evitados em favor dos moldes mais explícitos (e pesquisáveis!) Em estilo C ++ (por exemplo, static_cast ).

  • Finalmente, saiba como a regra de três:

    • Destructor
    • Copiar construtor
    • Operador de atribuição

    Tornou-se a regra de cinco com a adição do construtor de movimento e do operador de atribuição de movimento. E entenda as referências de valor em geral e como evitar a cópia.

C ++ é uma linguagem complexa, por isso é difícil caracterizar a melhor forma de usar todos . Mas as práticas de bom desenvolvimento em C ++ não mudaram fundamentalmente com o C ++ 11. Você ainda deve preferir contêineres gerenciados por memória com o gerenciamento manual de memória - os indicadores inteligentes facilitam isso de forma eficiente.

Eu diria que o C ++ moderno é na verdade livre de gerenciamento de memória manual - a vantagem do modelo de memória do C ++ é que ele é determinístico , não que seja manual. Desalocações previsíveis proporcionam um desempenho mais previsível.

Quanto a um compilador, o G ++ e o Clang são ambos competitivos em termos de recursos do C ++ 11, e rapidamente recuperam suas deficiências. Eu não uso o Visual Studio, então não posso falar nem contra nem contra isso.

Por fim, uma observação sobre std::for_each : evite isso em geral.

transform , accumulate e erase - remove_if são bons map , fold e filter funcionais. Mas for_each é mais geral e, portanto, menos significativo - não expressa qualquer intenção diferente de loop. Além disso, é usado nas mesmas situações que o for com base no intervalo e é sintaticamente mais pesado, mesmo quando usado sem pontos. Considere:

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);
    
por 23.10.2012 / 00:50
fonte
12

Como ponto de partida:

  • Pare de usar char* para strings. Use std::string ou std::wstring e observe seu código ficar mais curto, mais legível e mais seguro
  • Pare de usar matrizes no estilo C (coisas declaradas com [ ] ) e use std::vector ou alguma outra classe de contêiner apropriada. As coisas boas sobre std::vector são que ele conhece seu próprio tamanho, limpa seu conteúdo quando fica fora do escopo, é fácil fazer a iteração e se torna maior quando você adiciona mais itens. Mas há outras coleções que podem funcionar ainda melhor para suas circunstâncias.
  • Use std::unique_ptr - e aprenda std::move quase imediatamente. Como isso pode resultar em alguns objetos não-copiáveis, a preguiça pode ocasionalmente enviar você para std::shared_ptr - e você também pode ter alguns casos de uso genuínos para std::shared_ptr
  • Use auto ao declarar iteradores e tipos que dependam de declarações anteriores (por exemplo, antes de declarar um vetor de algo, agora você está declarando algo, use auto )
  • Use algoritmos e for_each em um "raw for" sempre que puder, pois isso poupa outras pessoas de lerem o loop cuidadosamente para concluir que você está de fato interagindo com toda a coleção, etc. Se o compilador suportar "intervalo para" em seguida, use-o sobre for_each . Aprenda chamadas de algoritmo triviais como iota , generate , accumulate , find_if e assim por diante.
  • Use lambdas - eles são a maneira mais fácil de alavancar algoritmos. Eles também abrem a porta para muito mais.

Não fique muito preocupado com o compilador a ser usado. A falta "terrível, horrível" do suporte ao C ++ 11 no VS2012 é que não há modelos variadic (sim, você estava praticamente para usar modelos variadic) e o {} initializer não é lá. Eu também quero isso, mas dificilmente vou parar de usar uma ferramenta de desenvolvimento útil.

A segunda coisa a fazer, depois de abraçar o std:: , é começar a pensar no RAII. Sempre que você tiver

  • ação inicial
  • série de ações com algo que você obteve ao iniciar a ação
  • ação de limpeza que precisa acontecer mesmo no caso de exceções

Então, o que você tem é um construtor, um número de funções de membro e um destruidor. Escreva uma aula que cuide disso para você. Você pode até não ter que escrever o ctor e o dtor. Colocar um shared_ptr como uma variável de membro de uma classe é um exemplo de RAII - você não escreve código de gerenciamento de memória, mas quando sua instância sai do escopo, as coisas certas vão acontecer. Expandir esse pensamento para cobrir coisas como fechar arquivos, liberar alças, bloqueios etc e código só vai ficar mais simples e menor (enquanto elimina vazamentos) diante de seus olhos.

Se você estiver realmente confiante, elimine printf em favor de cout , livre-se de macros ( #define stuff) e comece a aprender alguns "idiomas avançados" como PIMPL. Eu tenho um curso sobre este no Pluralsight que você provavelmente pode assistir usando o teste gratuito.

    
por 23.10.2012 / 13:13
fonte
3

How do I best learn to make use of these modern language features and which are suitable for which moments?

Por programação. A experiência é a melhor maneira de aprender.

O C ++ 11 tem muitos novos recursos (auto, rvalue, novos ponteiros inteligentes - só para citar alguns). O melhor começo é começar a usá-las e ler sobre elas sempre que puder e sempre que encontrar um artigo interessante.

Is it correct that software engineering in C++ nowadays is mostly free of manual memory management?

Isso depende do que você precisa fazer. A maioria dos aplicativos pode se dar bem com indicadores inteligentes e esquecer o gerenciamento de memória. Ainda existem aplicativos que não podem escapar tão facilmente (por exemplo, se precisarem de um novo posicionamento ou de um alocador de memória personalizado por qualquer motivo).

Se você precisar usar o Qt, terá que usar as regras deles para o gerenciamento de memória.

which compiler should I use to make the most of the new standard?

Qualquer coisa que você tenha em mãos que suporte o padrão mais recente:

mas nenhum compilador suporta todos os recursos.

    
por 23.10.2012 / 12:42
fonte
-7

Minha universidade ainda está usando o C ++ para o ensino. Eu tenho programado com C ++ por 5 anos e agora sou estudante de graduação. Claro, agora estou usando muito Java, Ruby etc. Eu realmente recomendo que você não tenha pressa sobre esses recursos em linguagem como Java. Na minha experiência e opinião, após os recursos de baixo nível do C ++. Você deve procurar tópicos como programação genérica com C / C ++, como criar classes de modelos, funções de modelos, operadores sobrescritos, métodos virtuais, ponteiros inteligentes. Para a Parte de Design Orientada 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, os segmentos, também são importantes no 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 ainda, 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 também fez. Para o compilador, o G ++ é bom do GNU.

Afinal de contas, depois de tantos anos, eu realmente sinto, as coisas mais importantes são os recursos de baixo nível, como array raw. Vector é realmente apenas um array dinâmico. Estas são minhas recomendações, algo talvez muito subjetivo, apenas tome o que você acha que está certo.

    
por 23.10.2012 / 03:25
fonte

Tags