Com o novo padrão, existem novas maneiras de fazer as coisas, e muitas são mais agradáveis que as antigas, mas a antiga ainda é boa. Também está claro que o novo padrão não obsoleta muito, por motivos de compatibilidade com versões anteriores. Portanto, a questão que resta é:
Quais formas antigas de codificação são definitivamente inferiores aos estilos C ++ 11 e o que podemos fazer agora?
Ao responder isso, você pode pular as coisas óbvias como "usar variáveis automáticas".
auto_ptr
, também está obsoleto.Respostas:
final
especificador para impedir a derivação de classestd::auto_ptr
trabalhos não são mais necessários devido ao suporte de primeira classe para referências de rvalor.shrink_to_fit()
função de membro, que deve eliminar a necessidade de troca por um temporário.= delete
sintaxe é uma maneira muito mais direta de dizer que uma funcionalidade específica é explicitamente negada. Isso é aplicável para impedir a alocação de heap (ou seja,=delete
para membrooperator new
), impedir cópias, atribuição, etc.result_of
: Os usos do modelo de classeresult_of
devem ser substituídos pordecltype
. Eu acho queresult_of
usadecltype
quando está disponível.NULL
deve ser redefinido comonullptr
, mas veja a palestra da STL para saber por que eles decidiram contra.Eu acho que vou parar por aí!
fonte
result_of
partir da lista. Apesar do incômodotypename
necessário antes, achotypename result_of<F(Args...)::type
que às vezes pode ser mais fácil de ler do quedecltype(std::declval<F>()(std::declval<Args>()...)
, e com a aceitação do N3436 no documento de trabalho que ambos trabalham para a SFINAE (que costumava ser uma vantagemdecltype
dissoresult_of
não oferecia)Em um determinado momento, argumentou-se que se deveria retornar por
const
valor, em vez de apenas por valor:Isso foi principalmente inofensivo no C ++ 98/03 e pode até ter detectado alguns bugs parecidos com:
Mas retornar por
const
é contra-indicado no C ++ 11, porque inibe a semântica de movimentos:Então, basta relaxar e codificar:
fonte
A& operator=(A o)&
vez deA& operator=(A o)
. Isso evita erros tolos e faz com que as classes se comportem mais como tipos básicos e não impedem a semântica de movimentos.Assim que você puder abandonar
0
e aNULL
favornullptr
, faça-o!No código não genérico, o uso
0
ouNULL
não é tão importante. Mas assim que você começa a passar constantes nulos de ponteiro no código genérico, a situação muda rapidamente. Quando você passa0
para atemplate<class T> func(T)
T
é deduzido como umaint
constante de ponteiro e não como nula. E não pode ser convertido novamente em um ponteiro nulo constante depois disso. Isso se transforma em uma confusão de problemas que simplesmente não existem se o universo fosse usado apenasnullptr
.O C ++ 11 não é preterido
0
eNULL
como constantes de ponteiro nulo. Mas você deve codificar como se fosse.fonte
std::nullptr_t
.0
ouNULL
para ponteiros nulos").Idioma seguro do bool →
explicit operator bool()
.Construtores de cópias privadas (boost :: noncopyable) →
X(const X&) = delete
Simulando a classe final com destruidor privado e herança virtual →
class X final
fonte
Uma das coisas que apenas o impede de escrever algoritmos básicos no C ++ 11 é a disponibilidade de lambdas em combinação com os algoritmos fornecidos pela biblioteca padrão.
Estou usando esses agora e é incrível quantas vezes você apenas diz o que deseja fazer usando count_if (), for_each () ou outros algoritmos, em vez de precisar escrever os malditos loops novamente.
Depois de usar um compilador C ++ 11 com uma biblioteca padrão completa do C ++ 11, você não tem mais uma boa desculpa para não usar algoritmos padrão para criar os seus . Lambda apenas mate-o.
Por quê?
Na prática (depois de ter usado essa maneira de escrever algoritmos), é muito mais fácil ler algo que é construído com palavras diretas que significam o que é feito do que com alguns loops que você precisa criptografar para saber o significado. Dito isso, deduzir automaticamente os argumentos lambda ajudaria muito a tornar a sintaxe mais facilmente comparável a um loop bruto.
Basicamente, os algoritmos de leitura feitos com algoritmos padrão são muito mais fáceis, pois as palavras escondem os detalhes da implementação dos loops.
Suponho que apenas algoritmos de nível superior precisam ser pensados agora que temos algoritmos de nível inferior para construir.
fonte
for_each
com um lambda seja melhor que o loop for baseado em intervalo equivalente, com o conteúdo do lambda no loop. O código parece mais ou menos o mesmo, mas o lambda introduz uma pontuação extra. Você pode usar equivalentes de coisas comoboost::irange
aplicá-lo a mais loops do que apenas aqueles que obviamente usam iteradores. Além disso, o loop for baseado em intervalo tem maior flexibilidade, pois você pode sair mais cedo, se necessário (porreturn
ou porbreak
), enquanto que comfor_each
você precisaria jogar.for
torna oit = c.begin(), const end = c.end(); it != end; ++it
idioma usual extinto.for_each
algoritmo no intervalo baseado no loop for é que você não podebreak
oureturn
. Ou seja, quando você vêfor_each
que sabe imediatamente, sem olhar para o corpo, que não há tal truque.std::for_each(v.begin(), v.end(), [](int &i) { ++i; });
comfor (auto &i : v) { ++i; }
. Aceito que a flexibilidade seja de dois gumes (goto
é muito flexível, esse é o problema). Eu não acho que a restrição de não ser capaz de usarbreak
nosfor_each
compensa versão para a verbosidade extra que exige - usuários defor_each
aqui são IMO sacrificar a legibilidade real e conveniência para uma espécie de noção teórica que ofor_each
é , em princípio, mais claro e conceitualmente mais simples. Na prática, não é mais claro ou mais simples.Você precisará implementar versões personalizadas com
swap
menos frequência. No C ++ 03,swap
muitas vezes é necessário um não lançamento eficiente para evitar cópias caras e de lançamento, e comostd::swap
usa duas cópias,swap
muitas vezes precisa ser personalizado. No C ++,std::swap
usamove
e, portanto, o foco muda na implementação de construtores de movimento eficientes e não arremessadores e operadores de atribuição de movimento. Como para esses o padrão geralmente é bom, isso será muito menos trabalhoso do que no C ++ 03.Geralmente, é difícil prever quais idiomas serão usados, pois são criados através da experiência. Podemos esperar um "C ++ 11 efetivo" talvez no próximo ano e um "Padrões de codificação C ++ 11" apenas em três anos, porque a experiência necessária ainda não existe.
fonte
Não sei o nome, mas o código C ++ 03 costumava usar a seguinte construção como um substituto para a atribuição de movimentação ausente:
Isso evitou qualquer cópia devido ao elision da cópia combinado com o
swap
acima.fonte
map
qualquer maneira. A técnica que você mostra é útil semap
já existe, em vez de apenas estar sendo construída. O exemplo seria melhor sem o comentário "construtor padrão barato" e com "// ..." entre essa construção e a trocaQuando notei que um compilador usando o padrão C ++ 11 não falha mais o seguinte código:
por supostamente conter o operador >>, comecei a dançar. Nas versões anteriores, seria preciso fazer
Para piorar as coisas, se você já teve que depurar isso, sabe como as mensagens de erro são horríveis.
Eu, no entanto, não sei se isso era "óbvio" para você.
fonte
Retorno por valor não é mais um problema. Com a semântica de movimentação e / ou as funções de codificação de otimização do valor de retorno (dependentes do compilador) são mais naturais, sem custos indiretos ou custos (na maioria das vezes).
fonte