Como mudar para o C ++ 11?

35

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.

Overv
fonte
2
Eu diria que chamar o suporte a C ++ 11 do VS2012 como "terrível" é um pouco exagerado, mas certamente poderia ser melhor (a falta de listas de inicializadores é especialmente irritante para o código de teste / brinquedo). Mas nota que eles anunciaram que estará enviando atualizações do compilador independentemente do resto da VS, então eu acho que podemos esperar alguns C ++ bastante 11 características em VS2012 no decorrer de 2013.
Martin Ba
3
No começo, pensei que sugerir isso para aprender C ++ 11 seria estranho, mas como você ainda está preso nas terras das classes C ... Uma década atrás, eu li o C ++ acelerado da Koenig / Moo . Na época, eu já estava na meta-programação de modelos (só li para uma revisão), mas ainda parecia uma revelação. (Eu o usei como base para o ensino de C ++ desde então.) Vindo de C Com as aulas , o livro pode mostrar um idioma totalmente novo que você não sabia que tinha à sua disposição. São apenas 250 páginas e, em seguida, você pode avançar rapidamente para algo específico do C ++ 11, mas a IMO é um passo que vale a pena.
S28 /
4
g++ -std=c++11
Fredoverflow

Respostas:

50

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);
Jon Purdy
fonte
6
Existem alguns princípios vinculativos para essas regras práticas? Parece uma boa lista de sugestões, mas ... Como um estranho que chega a essa pergunta pelo Google, como sua resposta me ajuda a pegar o C ++ 11 de uma maneira baseada em princípios e usá-lo sem me envolver no eixo C ++ ?
Robert Harvey
3
+1 para a lista, mas tenho um pequeno nitpick: quando (com razão) aviso contra, std::for_eacheu esperava que o intervalo baseado em loop fosse um substituto melhor que o normal for.
Fabio Fracassi
@FabioFracassi: Opa. Escrevi claramente para contrastar std::for_each, não com base em intervalo . Eu o removi para evitar confusão.
22412 Jon Purdy
11
Eu atualizaria se não fosse por std::for_each(). Quando você tem lambda, certamente é melhor que um forloop tradicional . Com um forloop baseado em intervalo que pode não ser o caso, mas você não escreveu " forloop baseado em intervalo ".
S28
@sbi: Na minha opinião, o termo " forloop" inclui " forloop baseado em faixa ". Eu editei com mais explicações e um exemplo para esclarecer, obrigado.
21412 Jon Purdy
12

Como ponto de partida:

  • Pare de usar char*para strings. Use std::stringou std::wstringobserve o seu código ficar mais curto, mais legível e mais seguro
  • Pare de usar matrizes no estilo C (itens declarados com [ ]) e use std::vectorou alguma outra classe de contêiner apropriada. O bom std::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.
  • Use std::unique_ptr- e aprenda std::movequase imediatamente. Uma vez que este pode resultar em alguns objetos noncopyable, preguiça pode ocasionalmente enviar-lhe direção std::shared_ptr- e você pode ter alguns casos de uso reais para std::shared_ptrbem
  • Use autoao declarar iteradores e tipos que dependem de declarações anteriores (por exemplo, anteriormente você declarou um vetor de algo, agora você está declarando algo, use auto)
  • Use algoritmos e for_eachsobre 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 novamente for_each. Saiba chamadas algoritmo triviais como iota, generate, accumulate, find_ife assim por diante.
  • Use lambdas - eles são a maneira mais fácil de aproveitar algoritmos. Eles também abrem a porta para muito mais.

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ê 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 ocorrer mesmo no caso de exceções

Entã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_ptrvariá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 printffavor cout, livre-se das macros ( #definecoisas) 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.

Kate Gregory
fonte
2
Eu gosto de como você é sarcástico em relação a ele não usar modelos variados tão cedo, mas acho que a falta de inicialização uniforme está faltando algo realmente importante para a programação diária.
S28 /
Mal posso esperar para initializer listas ... esperando para saber quando vamos levá-los ...
Kate Gregory
Outra falta importante no VS2012 são as "referências de valor v3", ou seja, o construtor de movimentação gerado automaticamente e a atribuição de movimentação.
Mr.C64
3

Como melhor aprendo a usar esses recursos da linguagem moderna e quais são adequados para quais momentos?

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.

É correto que a engenharia de software em C ++ atualmente esteja livre de gerenciamento manual de memória?

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.

qual compilador devo usar para aproveitar ao máximo o novo padrão?

Tudo o que você tem em mãos que suporta o padrão mais recente:

mas nenhum compilador suporta todos os recursos.

BЈовић
fonte
-7

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.

Sen Han
fonte
6
Como isso responde à pergunta? A questão não é aprender C ++ em geral, mas mudar para C ++ 11.
Roc Martí