Quelles sont les mauvaises habitudes des programmeurs C qui commencent à écrire en C ++?

Une discussion a récemment pris fin en mocking des mauvaises habitudes des programmeurs qui ont été trop exposés à une langue quand ils commencent à programmer dans une autre langue. Le meilleur exemple serait un programmeur Pascal commençant à #define begin { et #define end } en commençant à écrire C.

L’objective est d’essayer d’attraper les mauvaises habitudes des programmeurs C lorsqu’ils commencent à utiliser le C ++.

Parlez du gros ne que vous avez rencontré. Une suggestion par réponse, s’il vous plaît, d’essayer de réaliser une sorte de meilleur de.

Pour ceux qui sont intéressés par de bonnes habitudes, jetez un œil à la réponse acceptée à cette question .

Utilisation de pointeurs et de ressources bruts au lieu d’objects RAII.

  • en utilisant char * au lieu de std :: ssortingng
  • en utilisant des tableaux au lieu de std :: vector (ou d’autres conteneurs)
  • ne pas utiliser d’autres algorithmes ou bibliothèques STL comme boost, le cas échéant
  • abuser du préprocesseur où des constantes, des typedefs ou des templates auraient été mieux
  • écriture de code de type SESE (sortie unique à entrée unique)

Déclarer toutes les variables en haut d’une fonction au lieu d’être aussi proches que possible de l’endroit où elles sont utilisées.

Ne pas utiliser la STL, en particulier std :: ssortingng,

et / ou

en utilisant std :: ssortingngs et en revenant à l’ancienne fonction c ssortingng dans les virages serrés.

  1. Ecriture de définitions de classe de 2000 lignes de code
  2. Copier et coller cette définition de classe dans 12 endroits différents.
  3. Utiliser des instructions switch lorsqu’une méthode virtuelle simple suffirait.
  4. Échec d’allocation de mémoire dans le constructeur et de désallocation dans un destructeur.
  5. Méthodes virtuelles qui prennent des arguments optionnels.
  6. Écrire des boucles while pour manipuler les chaînes char *.
  7. Écriture de macro géantes d’une page. (Aurait pu utiliser des modèles à la place).

utiliser des pointeurs au lieu de références

Ajout de using dans les fichiers d’en-tête afin qu’ils puissent éviter des noms tels que std::ssortingng dans les déclarations de type.

Développeurs très expérimentés ne comprenant pas le casting ni même la programmation orientée object:

J’ai commencé à participer à un projet et l’un des frameworks supérieurs rencontrait un problème avec un code qui fonctionnait et qui ne fonctionnait plus.

(Les noms de classe ont été modifiés pour protéger l’innocent, et je ne me souviens pas des noms exacts) Il avait du code C ++ qui écoutait les classes de messages entrants et les lisait. Auparavant, une classe de message était transmise et il y interagissait avec une variable pour déterminer le type de message. Il transmettrait alors le message en C-style comme une autre classe spécialisée qu’il aurait écrite et héritée de Message. Cette nouvelle classe avait des fonctions qui extrayaient les données comme il le voulait. Cela fonctionnait bien pour lui, mais ce n’était pas le cas maintenant.

Après de nombreuses heures à parcourir son code, il ne voyait aucun problème et j’ai jeté un coup d’œil par-dessus son épaule. Immédiatement, je lui ai dit que ce n’était pas une bonne idée de lancer Message dans le style C à une classe dérivée, ce qui n’était pas le cas. Il était en désaccord avec moi et a dit qu’il le faisait depuis des années et que si c’était faux, alors tout ce qu’il fait est faux, car il utilise fréquemment cette approche. Il a ensuite été appuyé par un entrepreneur qui m’a dit que j’avais tort. Ils ont tous deux fait valoir que cela fonctionne toujours et que le code n’a pas changé, de sorte que ce n’est pas cette approche mais quelque chose qui a violé son code.

J’ai regardé un peu plus loin et j’ai trouvé la différence. La dernière version de la classe Message avait une fonction virtuelle et n’avait jamais utilisé le virtuel. J’ai dit aux deux personnes qu’il y avait maintenant une table virtuelle et que les fonctions étaient recherchées, etc., etc., et que cela posait problème, etc., etc. Ils ont fini par accepter et on m’a présenté un commentaire que je n’oublierai jamais: “La virtualité bloque complètement le polymorphism et la programmation orientée object”.

Je leur ai fait parvenir une copie d’un motif de décorateur pour illustrer comment append une fonction à une classe existante, mais je n’ai rien entendu en retour. Comment ils ont corrigé l’idée, je n’en ai aucune idée.

Un mot: les macros. Je ne dis pas que les macros n’ont aucune place en C ++, mais les anciens programmeurs C ont tendance à les utiliser beaucoup trop après avoir basculé en C ++.

Utilisation de moulages de style C.

C ++ vous permet de choisir indépendamment d’autoriser les conversions entre types non liés et de modifier volatile qualificatifs const et volatile , ce qui améliore considérablement la sécurité du type à la compilation par rapport à C. Il offre également des transmissions totalement sécurisées au prix d’une exécution. vérifier.

Les conversions en style C, les conversions non contrôlées entre presque tous les types, autorisent des classes entières d’erreur facilement identifiables par des conversions plus ressortingctives. Leur syntaxe les rend également très difficiles à rechercher, si vous souhaitez auditer le code source d’erreurs pour des conversions douteuses.

Écrire en using namespace std car tout le monde le fait et ne réfléchit jamais sur sa signification. Ou savoir ce que cela signifie, mais dire ” std::cout << "Hello World" << std::endl; air moche".

Passer des objects avec des pointeurs au lieu de références. Oui, vous avez encore parfois besoin de pointeurs en C ++, mais les références étant plus sûres, vous devez les utiliser quand vous le pouvez.

En supposant que lesdits programmeurs aient déjà commis l’erreur d’essayer d’apprendre le C ++:

Les erreurs

  • Ne pas utiliser STL.
  • Essayer de tout envelopper dans les classes.
  • Essayer d’utiliser des modèles pour tout.
  • Ne pas utiliser Boost. (Je sais que Boost peut être un véritable PITA et une courbe d’apprentissage, mais le C ++ n’est que du C + sans ce dernier. Boost donne des stacks au C ++).
  • Ne pas utiliser les pointeurs intelligents.
  • Ne pas utiliser RAII.
  • Utilisation excessive des exceptions.

Controversé

  • Passage en C ++. Ne le fais pas.
  • Essayez de convertir C stdio en iostreams. Iostreams SUX. Ne l’utilisez pas. C’est insortingnsèquement cassé. Regarde ici .
  • Utilisation des parties suivantes de la bibliothèque libstdc ++ :
    • cordes (au-delà de les libérer pour moi, allez-vous en enfer)
    • localisation (qu’est-ce que cela a à voir avec c ++, pire encore, c’est affreux)
    • entrée / sortie (décalage de fichier 64 bits? entendu parler d’eux)
  • En croyant naïvement que vous pouvez toujours déboguer sur la ligne de commande. N’utilisez pas le C ++ de manière intensive sans une grue de code (IDE).
  • Suivre les blogs C ++. Les blogs C ++ parlent de ce qui se résume essentiellement aux métadonnées et au sucre. Au-delà d’une bonne FAQ et de l’expérience, je n’ai pas encore vu de blog C ++ utile. (Notez que c’est un défi: j’aimerais lire un bon blog C ++.)

Rendre tout dans une classe publique. Ainsi, les membres de données qui devraient être privés ne le sont pas.

Pas complètement comprendre la sémantique des pointeurs et des références et quand utiliser l’un ou l’autre. En ce qui concerne les pointeurs, le problème est également de ne pas gérer correctement la mémoire allouée dynamic ou d’échouer à utiliser des constructions “plus intelligentes” pour cela (par exemple, les pointeurs intelligents).

Mon préféré est le programmeur C qui écrit une seule méthode avec plusieurs arguments facultatifs.

Fondamentalement, la fonction ferait différentes choses selon les valeurs et / ou la nullité des arguments.

Ne pas utiliser de modèles lors de la création d’algorithmes et de structures de données ( exemple ). Cela rend les choses trop localisées ou trop génériques

Ie écrit

 void qsort(MyStruct *begin, size_t length); //too localized void qsort(void *begin, size_t length, size_t rec_size, int(compare*)(void*,void*)); //too generic 

au lieu de

 template  void qsort(RA_Iter begin, size_t length); //uses RA_Iter::value_type::operator< for comparison 

Bien, une mauvaise conception de programme transcende les langages (castes, ignorant les avertissements, magie des précomstackurs non nécessaire, bidouillage inutile, ne pas utiliser les macros de classification des caractères), et le langage C lui-même ne crée pas trop de “mauvaises habitudes” (Ok, Macros, des âges de pierre), et de nombreux idiomes traduisent directement. Mais quelques-uns qui pourraient être considérés:

Utiliser une fonctionnalité simplement parce qu’elle est en C ++ et donc que cela doit être la bonne façon de faire quelque chose. Certains programmes n’ont tout simplement pas besoin d’inheritance, de MI, d’exceptions, de RTTI, de modèles (bien qu’ils soient … la charge de débogage est lourde), ou de choses de classe virtuelle.

S’en tenir à un extrait de code de C, sans se demander si C ++ a un meilleur moyen. (Il y a une raison pour laquelle vous avez maintenant des fonctions de classe, privées, publiques, const (développées au-delà de C89), des classes statiques, des références.

Ne pas être familiarisé avec C ++ i / o lib (son BIG, et vous devez le savoir), et mélanger C ++ i / o et C i / o.

Il pense que C ++ est un langage un peu plus différent de C. Il continuera à programmer C masqué par C ++. Pas d’utilisation avancée des classes, les structures sont considérées comme moins puissantes que les classes, les espaces de noms, les nouveaux en-têtes, les modèles, aucun de ces nouveaux éléments n’est utilisé. Il continuera à déclarer des entiers vars sans int, il ne fournira pas de fonctions prototypes. Il utilisera malloc et des pointeurs libres et dangereux, ainsi que des pré-processeurs, pour définir des fonctions inline. Ceci est juste une petite liste;)

Utilisations confuses de structures et de classes, surutilisation de méthodes globales prenant les pointeurs d’object comme arguments et pointeurs d’instance accessibles globalement

 extern Application* g_pApp; void RunApplication(Application* app, int flags); 

Aussi (ne dis pas que c’est totalement inutile, mais quand même):

 const void* buf; 

Déclarer toutes les variables au début de la fonction même si la variable ne sera utilisée qu’après 100 lignes environ.

Cela se produit surtout pour les variables locales déclarées dans une fonction.

Ne pas laisser assez seul et utiliser C à la place.

  1. Résoudre le problème au lieu de créer une monstruosité basée sur la classe vous garantira de restr dans l’assurance maladie et les avantages 401K.

  2. Implémenter lisp dans un seul fichier et en faire la conception.

  3. Écrire des fonctions lisibles normales au lieu de remplacer des opérateurs?

  4. Écrire dans un style compréhensible pour les programmeurs débutants qui considèrent les bonnes pratiques comme “ne pas écrire en C ++”.

  5. Parler à l’OS dans sa propre langue.