web-dev-qa-db-fra.com

Quels idiomes C ++ sont déconseillés en C ++ 11?

Avec la nouvelle norme, il existe de nouvelles façons de faire les choses, et beaucoup sont plus agréables que les anciennes, mais l'ancienne est toujours valable. Il est également clair que la nouvelle norme ne déprécie pas officiellement beaucoup, pour des raisons de compatibilité ascendante. La question qui reste est donc:

Quelles anciennes méthodes de codage sont nettement inférieures aux styles C++ 11 et que pouvons-nous faire maintenant à la place?

En répondant à cette question, vous pouvez sauter les choses évidentes telles que "utiliser des variables automatiques".

189
Alan Baljeu
  1. Final Class : C++ 11 fournit le spécificateur final pour empêcher la dérivation de classe.
  2. Les lambdas C++ 11 réduisent considérablement le besoin de classes d'objet de fonction nommée (foncteur).
  3. Constructeur du déplacement : Les méthodes magiques avec lesquelles std::auto_ptr Fonctionne ne sont plus nécessaires en raison de la prise en charge de première classe des références rvalue.
  4. Safe Bool : Cela a été mentionné plus tôt. Les opérateurs explicites de C++ 11 évitent cet idiome très commun de C++ 03.
  5. Shrink-to-fit : De nombreux conteneurs STL C++ 11 fournissent une fonction membre shrink_to_fit(), ce qui devrait permettre d'éviter l'échange de données par un temporaire.
  6. Classe de base temporaire : Certaines anciennes bibliothèques C++ utilisent cet idiome plutôt complexe. Avec la sémantique de déplacement, ce n'est plus nécessaire.
  7. Type Safe Enum Les énumérations sont très sûres en C++ 11.
  8. Interdiction de l'allocation de tas : La syntaxe = delete Est une façon beaucoup plus directe de dire qu'une fonctionnalité particulière est explicitement refusée. Ceci s’applique pour empêcher l’allocation de tas (c.-à-d., =delete Pour le membre operator new), Empêcher les copies, les affectations, etc.
  9. Typedef basé sur un modèle : Modèles d'alias dans C++ 11, réduisez le recours à de simples typedefs basés sur un modèle. Cependant, les générateurs de types complexes ont toujours besoin de méta-fonctions.
  10. Certains calculs numériques au moment de la compilation, tels que Fibonacci, peuvent être facilement remplacés à l'aide de expressions constantes généralisées
  11. result_of : Les utilisations du modèle de classe result_of Doivent être remplacées par decltype. Je pense que result_of Utilise decltype quand il est disponible.
  12. initialiseurs de membres de classe enregistrer en tapant pour l'initialisation par défaut des membres non statiques avec des valeurs par défaut.
  13. Dans le nouveau code C++ 11, NULL devrait être redéfini en tant que nullptr, mais voyez conversation de STL pour savoir pourquoi ils l'ont décidé.
  14. Modèle d'expression les fanatiques sont ravis d'avoir la syntaxe de la fonction type de retour final en C++ 11. Finis les types de retour long sur 30 lignes!

Je pense que je vais m'arrêter là!

171
Sumant

À un moment donné, on a prétendu qu'il fallait retourner par valeur const plutôt que par valeur:

const A foo();
^^^^^

C'était en grande partie inoffensif en C++ 98/03, et peut même avoir attrapé quelques bugs qui ressemblaient à:

foo() = a;

Mais retourner par const est contre-indiqué en C++ 11 car il inhibe la sémantique de déplacement:

A a = foo();  // foo will copy into a instead of move into it

Alors détendez-vous et codez:

A foo();  // return by non-const value
65
Howard Hinnant

Dès que vous pouvez abandonner 0 Et NULL en faveur de nullptr, faites-le!

Dans le code non générique, l'utilisation de 0 Ou NULL n'est pas si grave. Mais dès que vous commencez à transmettre des constantes de pointeur nul dans le code générique, la situation change rapidement. Lorsque vous transmettez 0 À une template<class T> func(T)T, elle est déduite en tant que int et non en tant que constante de pointeur null. Et il ne peut pas être reconverti en constante de pointeur null après cela. Cela tombe dans un bourbier de problèmes qui n'existent tout simplement pas si l'univers n'utilisait que nullptr.

C++ 11 ne déprécie pas 0 Et NULL en tant que constantes de pointeur nul. Mais vous devriez coder comme si c'était le cas.

61
Howard Hinnant

idiome de sécurité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 virtuelclass X final

38
kennytm

Une des choses qui vous empêche simplement d'écrire des algorithmes de base en C++ 11 est la disponibilité de lambdas en combinaison avec les algorithmes fournis par la bibliothèque standard.

J'utilise ceux-ci maintenant et c'est incroyable combien de fois vous dites simplement ce que vous voulez faire en utilisant count_if (), for_each () ou d'autres algorithmes au lieu d'avoir à écrire à nouveau ces fichues boucles.

Une fois que vous utilisez un compilateur C++ 11 avec une bibliothèque standard complète C++ 11, vous n’avez plus aucune excuse pour ne pas utiliser les algorithmes standard pour construire le vôtre. Lambda juste le tuer.

Pourquoi?

En pratique (après avoir utilisé moi-même cette méthode d'écriture d'algorithmes), il est beaucoup plus facile de lire quelque chose qui est construit avec des mots simples qui veulent dire ce qui est fait plutôt qu'avec certaines boucles qu'il faut déchiffrer pour en connaître le sens. Cela dit, déduire automatiquement les arguments lambda aiderait beaucoup à rendre la syntaxe plus facilement comparable à une boucle brute.

Fondamentalement, les algorithmes de lecture réalisés avec des algorithmes standard sont beaucoup plus faciles que des mots masquant les détails d'implémentation des boucles.

J'imagine que seuls les algorithmes de niveau supérieur doivent être pris en compte maintenant que nous avons des algorithmes de niveau inférieur sur lesquels s'appuyer.

24
Klaim

Vous devrez moins souvent implémenter des versions personnalisées de swap. En C++ 03, un swap non-jetable efficace est souvent nécessaire pour éviter les copies coûteuses et jettées, et depuis std::swap utilise deux copies, swap doit souvent être personnalisé. En C++, std::swap utilise move, et donc l’accent est mis sur l’implémentation de constructeurs de mouvements efficaces et non générateurs et d’opérateurs d’affectation de déplacements. Comme pour ceux-ci, la valeur par défaut est souvent correcte, 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. Nous pouvons nous attendre à un "Effective C++ 11" peut-être l'année prochaine, et à un "Standard de codage C++ 11" dans trois ans seulement, car l'expérience nécessaire fait défaut.

10
Philipp

Je ne connais pas son nom, mais le code C++ 03 a souvent utilisé la construction suivante pour remplacer l'affectation de déplacement manquante:

std::map<Big, Bigger> createBigMap(); // returns by value

void example ()
{
  std::map<Big, Bigger> map;

  // ... some code using map

  createBigMap().swap(map);  // cheap swap
}

Cela évitait toute copie en raison de la copie combinée avec le swap ci-dessus.

2
Andrzej

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épendant du compilateur), les fonctions de codage sont plus naturelles, sans surcoût ni coût (la plupart du temps).

1
Martin A

Quand j'ai remarqué qu'un compilateur utilisant le standard C++ 11 ne corrige plus le code suivant:

std::vector<std::vector<int>> a;

pour soi-disant opérateur contenant >>, j'ai commencé à danser. Dans les versions précédentes, il faudrait faire

std::vector<std::vector<int> > a;

Pour aggraver les choses, si jamais vous deviez déboguer ceci, vous savez à quel point les messages d'erreur qui en résultent sont horribles.

Cependant, je ne sais pas si cela vous paraissait "évident".

1
v010dya