Avec la nouvelle norme, il existe de nouvelles façons de faire les choses, et beaucoup sont plus agréables que les anciennes méthodes, mais l'ancienne méthode est toujours bonne. Il est également clair que la nouvelle norme n'est pas officiellement obsolète, pour des raisons de compatibilité descendante. La question qui reste est donc:
Quelles anciennes méthodes de codage sont définitivement inférieures aux styles C ++ 11, et que pouvons-nous faire maintenant à la place?
En répondant à cela, vous pouvez sauter les choses évidentes comme "utiliser des variables automatiques".
auto_ptr
est également obsolète.Réponses:
final
spécificateur pour empêcher la dérivation de classestd::auto_ptr
travaux ne sont plus nécessaires en raison du support de première classe des références rvalue.shrink_to_fit()
fonction membre, ce qui devrait éliminer le besoin d'échanger avec un fichier temporaire.= delete
syntaxe est une manière beaucoup plus directe de dire qu'une fonctionnalité particulière est explicitement refusée. Ceci est applicable pour empêcher l'allocation de tas (c'est-à-dire=delete
pour le membreoperator new
), empêcher les copies, l'affectation, etc.result_of
: Les utilisations du modèle de classeresult_of
doivent être remplacées pardecltype
. Je penseresult_of
utilisedecltype
quand il est disponible.NULL
devrait être redéfini commenullptr
, mais voyez le discours de STL pour savoir pourquoi ils ont décidé de ne pas le faire.Je pense que je vais m'arrêter là!
la source
result_of
de la liste. Malgré la lourdeurtypename
nécessaire avant cela, je pense que celatypename result_of<F(Args...)::type
peut parfois être plus facile à lire quedecltype(std::declval<F>()(std::declval<Args>()...)
, et avec l'acceptation de N3436 dans le document de travail, ils travaillent tous les deux pour SFINAE (qui était autrefois un avantage dedecltype
celaresult_of
n'a pas offert)À un moment donné, on a fait valoir qu'il fallait renvoyer par
const
valeur au lieu de simplement par valeur:C'était pour la plupart inoffensif en C ++ 98/03, et peut même avoir détecté quelques bogues qui ressemblaient à:
Mais le retour par
const
est contre-indiqué en C ++ 11 car il inhibe la sémantique de déplacement:Alors détendez-vous et codez:
la source
A& operator=(A o)&
au lieu deA& operator=(A o)
. Ceux-ci évitent les erreurs stupides et font que les classes se comportent davantage comme des types de base et n'empêchent pas la sémantique de déplacement.Dès que vous pouvez abandonner
0
etNULL
en faveur denullptr
, faites-le!Dans le code non générique, l'utilisation de
0
ouNULL
n'est pas si grave. Mais dès que vous commencez à transmettre des constantes de pointeur nulles dans du code générique, la situation change rapidement. Lorsque vous passez0
à a, iltemplate<class T> func(T)
T
est déduit comme unint
et non comme une constante de pointeur nul. Et il ne peut pas être reconverti en une constante de pointeur nul après cela. Cela tombe en cascade dans un bourbier de problèmes qui n'existent tout simplement pas si l'univers est utilisé uniquementnullptr
.C ++ 11 n'est pas obsolète
0
et enNULL
tant que constantes de pointeur nul. Mais vous devez coder comme si c'était le cas.la source
std::nullptr_t
.0
ouNULL
pour des pointeurs nuls»).Idiome booléen sûr →
explicit operator bool()
.Constructeurs de copie privée (boost :: noncopyable) →
X(const X&) = delete
Simulation de la classe finale avec destructeur privé et héritage virtuel →
class X final
la source
L'une des choses qui vous évite d'écrire des algorithmes de base en C ++ 11 est la disponibilité des lambdas en combinaison avec les algorithmes fournis par la bibliothèque standard.
J'utilise ceux-ci maintenant et c'est incroyable à quelle fréquence vous dites simplement ce que vous voulez faire en utilisant count_if (), for_each () ou d'autres algorithmes au lieu d'avoir à réécrire les foutues boucles.
Une fois que vous utilisez un compilateur C ++ 11 avec une bibliothèque standard C ++ 11 complète, vous n'avez plus de bonne excuse pour ne pas utiliser d'algorithmes standard pour construire le vôtre . Lambda juste le tuer.
Pourquoi?
En pratique (après avoir moi-même utilisé cette façon d'écrire des algorithmes), il semble beaucoup plus facile de lire quelque chose qui est construit avec des mots simples signifiant ce qui est fait qu'avec des boucles qu'il faut déchiffrer pour en connaître le sens. Cela dit, faire déduire automatiquement des arguments lambda aiderait beaucoup à rendre la syntaxe plus facilement comparable à une boucle brute.
Fondamentalement, la lecture d'algorithmes réalisés avec des algorithmes standard est beaucoup plus facile car les mots masquent les détails d'implémentation des boucles.
Je suppose que seuls les algorithmes de niveau supérieur doivent être considérés maintenant que nous avons des algorithmes de niveau inférieur sur lesquels nous appuyer.
la source
for_each
qu'avec un lambda, c'est mieux que la boucle for équivalente basée sur la plage, avec le contenu du lambda dans la boucle. Le code a plus ou moins le même aspect, mais le lambda introduit une ponctuation supplémentaire. Vous pouvez utiliser des équivalents de choses comme l'boost::irange
appliquer à plus de boucles que celles qui utilisent évidemment des itérateurs. De plus, la boucle for basée sur la plage a une plus grande flexibilité, en ce sens que vous pouvez quitter tôt si nécessaire (parreturn
ou parbreak
), alors qu'avecfor_each
vous auriez besoin de lancer.for
fait disparaître l'it = c.begin(), const end = c.end(); it != end; ++it
idiome habituel .for_each
algorithme sur la plage basée sur la boucle for est que vous ne pouvez pasbreak
oureturn
. Autrement dit, lorsque vous voyez,for_each
vous savez immédiatement sans regarder le corps qu'il n'y a pas une telle ruse.std::for_each(v.begin(), v.end(), [](int &i) { ++i; });
avecfor (auto &i : v) { ++i; }
. J'accepte que la flexibilité soit à double tranchant (goto
c'est très flexible, c'est le problème). Je ne pense pas que la contrainte de ne pas pouvoir utiliserbreak
dans lafor_each
version compense la verbosité supplémentaire qu'elle exige - les utilisateurs d'for_each
ici sont l'OMI sacrifiant la lisibilité et la commodité réelles pour une sorte de notion théorique quifor_each
est en principe plus claire et conceptuellement plus simple. En pratique, ce n'est ni plus clair ni plus simple.Vous devrez implémenter des versions personnalisées
swap
moins souvent. En C ++ 03, un non-throwing efficaceswap
est souvent nécessaire pour éviter des copies coûteuses et lancées, et commestd::swap
utilise deux copies,swap
il doit souvent être personnalisé. En C ++,std::swap
utilisemove
, et donc l'accent est mis sur l'implémentation de constructeurs de déplacement et d'opérateurs d'affectation de déplacement efficaces et non lanceurs. Comme pour ceux-ci, la valeur par défaut est souvent très bien, ce sera beaucoup moins de travail qu'en C ++ 03.En général, il est difficile de prédire quels idiomes seront utilisés car ils sont créés par l'expérience. On peut s'attendre à un «C ++ 11 efficace» peut-être l'année prochaine, et à des «normes de codage C ++ 11» seulement dans trois ans car l'expérience nécessaire n'est pas encore là.
la source
Je ne connais pas le nom, mais le code C ++ 03 utilisait souvent la construction suivante en remplacement de l'affectation de déplacement manquante:
Cela a évité toute copie en raison de l'élision de copie combinée à ce qui
swap
précède.la source
map
toute façon la valeur de retour . La technique que vous montrez est utile si ellemap
existe déjà, plutôt que d'être simplement construite. L'exemple serait meilleur sans le commentaire "cheap default constructor" et avec "// ..." entre cette construction et le swapQuand j'ai remarqué qu'un compilateur utilisant le standard C ++ 11 ne comporte plus de défauts avec le code suivant:
pour soi-disant contenant opérateur >>, j'ai commencé à danser. Dans les versions antérieures, il fallait faire
Pour aggraver les choses, si jamais vous deviez déboguer cela, vous savez à quel point les messages d'erreur qui en découlent sont horribles.
Cependant, je ne sais pas si cela vous était "évident".
la source
Le retour par valeur n'est plus un problème. Avec la sémantique de déplacement et / ou l'optimisation de la valeur de retour (dépendante du compilateur), les fonctions de codage sont plus naturelles sans frais généraux ni coût (la plupart du temps).
la source