Les pires pratiques en C ++, les erreurs les plus courantes [fermé]


35

Après avoir lu ce fameux discours de Linus Torvalds , je me suis demandé quels étaient en réalité tous les pièges pour les programmeurs en C ++. Je ne fais pas explicitement référence aux fautes de frappe ou au mauvais déroulement du programme tel qu'il est traité dans cette question et ses réponses , mais à un plus grand nombre d'erreurs de haut niveau qui ne sont pas détectées par le compilateur et qui ne génèrent pas de bugs évidents au premier lancement, mais d'erreurs de conception complètes, Ce qui est improbable en C mais qui est susceptible d’être fait en C ++ par les nouveaux arrivants qui ne comprennent pas toutes les implications de leur code.

Je me réjouis également des réponses soulignant une baisse considérable des performances, à laquelle on ne s'attend généralement pas. Voici un exemple de ce qu'un de mes professeurs m'a dit à propos d'un générateur d'analyseur syntaxique LR (1):

Vous avez utilisé un peu trop d'instances d'héritage et de virtualité inutiles. L'héritage rend une conception beaucoup plus compliquée (et inefficace en raison du sous-système RTTI (inférence de type au moment de l'exécution)) et ne doit donc être utilisée que là où cela est utile, par exemple pour les actions de la table d'analyse. Parce que vous utilisez beaucoup les modèles, vous n’avez pratiquement pas besoin d’héritage. "


6
Certaines des erreurs les plus graves que vous puissiez commettre en C / C ++ sont principalement dues à l'héritage C ... lisez le comportement non défini, la gestion manuelle de la mémoire, etc. De plus, le conseil du prof semble faux / faux un expert en C ++) - L’instanciation de template devrait donner une classe normale avec vtable pour les virtualfonctions, non?

8
Vous vous souvenez peut-être mal de ce que votre professeur a dit ou il ne savait pas de quoi il parlait. Les classes dérivées n'ont généralement pas besoin d'utiliser RTTI (réflexion AKA) pour rechercher des éléments. S'ils utilisent des méthodes virtuelles, le code peut nécessiter une recherche vtable pour la répartition, mais cela se traduit par une seule instruction ASM sur de nombreux processeurs. En raison de problèmes de mise en cache, cela peut ralentir un peu les choses, mais vous ne remarquerez probablement jamais les frais généraux dans les cas d'utilisation les plus exigeants. Il existe de nombreuses bonnes raisons d'éviter le C ++, mais les recherches sur vtable n'en font pas partie.
Mason Wheeler

5
@FelixDombek: En termes si génériques et appliqués à tous les niveaux, cette citation de votre professeur montre une énorme ignorance. Lorsque votre conception a besoin d’un polymorphisme d’exécution, l’utilisation de fonctions virtuelles est souvent le meilleur choix; ne l'utilisez pas lorsque vous n'en avez pas besoin: vous n'avez pas besoin que toutes les méthodes soient virtuelles simplement parce que vous utilisez des classes dérivées, par exemple.
Fred Nurk

5
@Mason Wheeler: RTTI contient des informations sur le type, suffisantes pour pouvoir déterminer si un dynamic_castdoit réussir ou non, et peu d'autres choses, mais la réflexion en couvre beaucoup plus, notamment le fait de pouvoir récupérer des informations sur les attributs ou les fonctions des membres, ce qui n'est pas le cas. présent en C ++.
David Rodríguez - dribeas

5
Le commentaire du professeur est quelque peu décevant, car l'héritage et les fonctions virtuelles ne sont pas un gros problème de performance. Le conseil d'utiliser parcimonieusement l'héritage est bon, mais c'est davantage un problème de structure de programme que d'efficience. L'héritage, en particulier avec les membres protégés, est un couplage aussi étroit que possible, et si vous n'en avez pas besoin, vous ne devriez pas l'utiliser.
David Thornley

Réponses:


69

Torvalds parle de son cul ici.


OK, pourquoi il parle de son cul:

Tout d’abord, son discours n’est vraiment rien MAIS un discours. Il y a très peu de contenu réel ici. La seule raison pour laquelle il est vraiment célèbre ou même légèrement respecté est qu’il a été créé par Dieu Linux. Son principal argument est que le C ++ est une merde et qu'il aime faire chier les gens du C ++. Il n'y a bien sûr aucune raison de répondre à cela et quiconque considère cela comme un argument raisonnable est au-delà de la conversation.

En ce qui concerne ce qui pourrait être lu comme ses points les plus objectifs:

  • STL et Boost sont de la merde totale <- peu importe. Tu es un idiot.
  • STL et Boost provoquent une quantité infinie de douleurs <- ridicule. Évidemment, il exagère délibérément, mais alors quelle est sa véritable déclaration ici? Je ne sais pas. Il est plus que trivialement difficile de résoudre les problèmes lorsque vous faites vomir le compilateur dans Spirit ou quelque chose du genre, mais ce n'est ni plus ni moins difficile à résoudre que le débogage de l'UB causé par une mauvaise utilisation des constructions C comme void *.
  • Les modèles abstraits encouragés par C ++ sont inefficaces. <- Comme quoi? Il ne se développe jamais, ne fournit jamais d'exemples de ce qu'il veut dire, il le dit simplement. BFD. Étant donné que je ne peux pas dire de quoi il parle, il est inutile de "réfuter" la déclaration. C'est un mantra commun de C bigots mais cela ne le rend pas plus compréhensible ou intelligible.
  • Une utilisation correcte du C ++ signifie que vous vous limitez aux aspects C. <- En fait, le code WORSE C ++ le fait, donc je ne connais toujours pas WTF dont il parle.

En gros, Torvalds parle de son cul. Il n'y a pas d'argument intelligible fait pour rien. S'attendre à une réfutation sérieuse de telles absurdités est tout simplement ridicule. On me dit de "développer" une réfutation de quelque chose que je serais censé développer si c'est là où je l'ai dit. Si vous regardez vraiment, honnêtement, ce que Torvalds a dit, vous verrez qu'il n'a rien dit.

Tout simplement parce que Dieu dit que cela ne signifie pas que cela a un sens ou doit être pris plus au sérieux que si un bozo aléatoire le disait. À vrai dire, Dieu n'est qu'un autre bozo aléatoire.


Répondre à la question réelle:

La pire et la plus courante des mauvaises pratiques C ++ est de la traiter comme un C. L’utilisation continue des fonctions de l’API C comme printf, gets (également considéré comme mauvais en C), strtok, etc. ne manque pas seulement de tirer parti de la puissance fournie par le système de types plus étroit, ils entraînent inévitablement de nouvelles complications lorsqu’on essaie d’interagir avec du "vrai" code C ++. Donc, fondamentalement, faites exactement le contraire de ce que Torvalds conseille.

Apprenez à tirer parti des technologies STL et Boost pour mieux détecter les bogues en temps voulu et pour vous simplifier la vie de manière générale (le tokenizer boost, par exemple, est à la fois dactylographié et de meilleure qualité). Il est vrai que vous devrez apprendre à lire les erreurs de modèle, ce qui est déconcertant au début, mais (d'après mon expérience, c'est beaucoup plus facile que d'essayer de déboguer quelque chose qui génère un comportement indéfini pendant l'exécution, ce que l'API C fait assez facile à faire.

Pour ne pas dire que C n'est pas aussi bon. Bien sûr, j'aime mieux le C ++. Les programmeurs C aiment mieux C Il y a des compromis et des goûts subjectifs en jeu. Il y a aussi beaucoup de désinformation et de FUD qui circulent. Je dirais qu'il y a plus de FUD et de désinformation autour du C ++, mais je suis partial à cet égard. Par exemple, les problèmes de "gonflement" et de "performance" supposés du C ++ ne sont en réalité pas des problèmes majeurs la plupart du temps et sont certainement dépassés par les proportions de la réalité.

En ce qui concerne les problèmes auxquels votre professeur fait référence, ceux-ci ne sont pas propres au C ++. En programmation orientée objet (et en programmation générique), vous souhaitez préférer la composition à l'héritage. L'héritage est la relation de couplage la plus forte possible existant dans tous les langages OO. C ++ en ajoute un qui est plus fort, l'amitié. L'héritage polymorphe devrait être utilisé pour représenter des abstractions et les relations "est-un", il ne devrait jamais être utilisé pour une réutilisation. Il s'agit de la deuxième erreur la plus importante que vous puissiez commettre en C ++. C'est une erreur assez importante, mais elle est loin d'être unique en son genre. Vous pouvez également créer des relations d'héritage trop complexes en C # ou en Java, et ils auront exactement les mêmes problèmes.


1
Ironiquement, comme bien après 2007, git n’exécutait que des versions portables de Linux. Eh bien, tout système semblable à Unix. Encore une fois, étant donné les circonstances qui ont conduit à la création de git, je ne le lui reproche certainement pas.
Chris K

9
Linus a du mal à trouver un bon programmeur C ++ qui veuille travailler pour lui. Se demander pourquoi? Je pense que ce n'est qu'un problème de type œuf et poule.
Bo Persson

19

J'ai toujours pensé que les dangers du C ++ étaient fortement exagérés par des programmeurs inexpérimentés, C avec Classes.

Oui, le C ++ est plus difficile à maîtriser que quelque chose comme Java, mais si vous programmez à l'aide de techniques modernes, il est assez facile d'écrire des programmes robustes. Je n'ai pas honnêtement que beaucoup plus difficile d'une programmation de temps en C ++ que je fais dans des langages comme Java, et je me retrouve souvent l' absence de certaines abstractions C ++ comme modèles et RAII quand je conception dans d' autres langues.

Cela dit, même après des années de programmation en C ++, de temps en temps, je commettrai une erreur vraiment stupide qui ne serait pas possible dans un langage de niveau supérieur. Un défaut courant en C ++ est d’ignorer la durée de vie des objets: en Java et C #, vous n’avez généralement pas à vous soucier de la durée de vie des objets *, car tous les objets existent sur le tas et sont gérés pour vous par un récupérateur de déchets magique.

Maintenant, en C ++ moderne, vous n'avez généralement pas à vous soucier de la durée de vie d'un objet. Vous avez des destructeurs et des pointeurs intelligents qui gèrent pour vous la durée de vie des objets. 99% du temps, cela fonctionne à merveille. Mais de temps en temps, vous vous ferez toucher par un pointeur (ou une référence) suspendu. Par exemple, tout récemment, j'avais un objet (appelons-le Foo) qui contenait une variable de référence interne à un autre objet (appelons-le Bar). À un moment donné, j’ai arrangé bêtement les choses de manière à ce que cela Bardevienne hors de portée auparavant Foo, Foole destructeur de yet a fini par appeler une fonction membre de Bar. Inutile de dire que les choses ne se sont pas bien passées.

Maintenant, je ne peux pas vraiment blâmer le C ++ pour cela. C'était ma propre mauvaise conception, mais le fait est que ce genre de chose ne se produirait pas dans un langage géré de niveau supérieur. Même avec des pointeurs intelligents et similaires, il est parfois nécessaire de rester conscient de la durée de vie d'un objet.


* Si la ressource gérée est de la mémoire, alors.


8
Ne devez jamais vraiment vous soucier de la durée de vie d'un objet en Java et en C #? Leur GC s'occupe de la mémoire, mais ce n'est qu'une petite partie de RAII pour moi; Regardez les différentes interfaces "jetables" de ces langages, par exemple.
Fred Nurk

Devoir se préoccuper de la durée de vie d'un objet serait rare en Java, à l'exception de la conception peu pratique de sa bibliothèque d'E / S.
dan04

Votre problème de référence en suspens est quelque chose que je suis intéressé à essayer de résoudre. J'ai commencé une discussion sur mon blog sur la direction dans laquelle je me dirigeais pour le résoudre (promesses de pointeur). Fondamentalement, je pense que le langage pourrait utiliser quelques pointeurs plus intelligents. Prenez part à cette discussion si cela vous intéresse. Personne d'autre ne l'a été de la sorte ... mais si c'est quelque chose que vous aimeriez voir résolu, je rencontre le problème plus de 10% du temps.
Edward Strange

13

La différence de code est généralement plus liée au programmeur qu'au langage. En particulier, un bon programmeur C ++ et un programmeur C trouveront des solutions similaires (même différentes). Maintenant, C est un langage plus simple (en tant que langage) et cela signifie qu'il y a moins d'abstractions et plus de visibilité sur ce que le code fait réellement.

Une partie de son discours (il est connu pour ses discours contre le C ++) est basé sur le fait que davantage de personnes s’intéressent au C ++ et écrivent du code sans vraiment comprendre ce que certaines abstractions cachent et faire de fausses suppositions.


3
Quel est le coût d'itération sur une std::vector<bool>modification de chaque valeur? for ( std::vector<bool>::iterator it = v.begin(), end = v.end(); it != end; ++it ) { *it = !*it; }? Qu'est-ce qui est abstrait *it = !*it;?
David Rodríguez - dribeas le

2
Bien qu'il puisse être injuste de choisir des abominations linguistiques spécifiques largement critiquées comme des erreurs ...
Fred Nurk

2
@Fred Nurk: std::vector<bool>c'est une erreur bien connue, mais c'est un très bon exemple de ce qui est discuté: les abstractions sont bonnes, mais vous devez faire attention à ce qu'elles cachent. La même chose peut et va se passer dans le code utilisateur. Pour commencer, j’ai vu des utilisateurs de C ++ et de Java utiliser des exceptions pour effectuer un contrôle de flux et un code qui ressemble à un appel de fonction imbriquée qui est en fait un lanceur d’exception de sauvetage: void endOperation();implémenté sous throw EndOperation;. Un bon programmeur évitera ces constructions surprenantes , mais le fait est que vous pouvez les trouver.
David Rodríguez - dribeas le

5
Un des points de Torvalds est le suivant: il peut chasser les débutants simplement en choisissant C sur C ++ (il semble y avoir plus de débutants en C ++) et C ++ étant plus complexe, la courbe d’apprentissage est plus raide et il ya plus de chances de trébucher dans un coin. .
David Rodríguez - dribeas

2
+1, c'est exactement ce dont se plaint Linus. Il se veut anti-C ++, mais ce n'est pas vraiment le cas. Il est seulement anti-C ++ - programmeur.
Greyfade

13

Surutilisation de try/catchblocs.

File file("some.txt");
try
{
  /**/

  file.close();
}
catch(std::exception const& e)
{
  file.close();
}

Cela provient généralement de langages tels que Java et les gens diront que C ++ manque de finalizeclause.

Mais ce code présente deux problèmes:

  • Il est nécessaire de construire fileavant try/catch, car vous ne pouvez pas créer de closefichier qui n’existe pas dans catch. Cela conduit à une "fuite de champ" dans ce qui fileest visible après avoir été fermé. Vous pouvez ajouter un bloc mais ...: /
  • Si quelqu'un vient et ajoute un returnau milieu de la tryportée, le fichier n'est pas fermé (c'est pourquoi les gens reprochent à l'absence de finalizeclause)

Cependant, en C ++, nous avons des moyens beaucoup plus efficaces de traiter ce problème que:

  • Java finalize
  • C # using
  • Go's defer

Nous avons RAII, dont la propriété vraiment intéressante est le mieux résumée SBRM(gestion des ressources limitées).

En fabriquant la classe de sorte que son destructeur nettoie les ressources dont il est propriétaire, nous ne confions pas la responsabilité de la gestion de la ressource à chacun de ses utilisateurs!

C'est la fonctionnalité qui me manque dans n'importe quelle autre langue, et probablement celle qui est la plus oubliée.

La vérité est qu’il est rarement nécessaire d’écrire un try/catchbloc en C ++, si ce n’est au plus haut niveau, afin d’éviter la résiliation sans journalisation.


1
Je ne pense pas que ce soit l'influence de Java autant qu'il de C. (Vous pouvez remplacer directement fopenet fcloseici.) RAII est la façon « correcte » de faire les choses, mais il est peu pratique pour les gens qui veulent utiliser les bibliothèques C de C ++ .
dan04

Pour ce type de réponse, fournir un exemple de la solution correcte aurait été approprié.
Claus Jørgensen

@ ClausJørgensen: Eh bien, la solution n'est malheureusement pas vraiment "voyante", car elle implique juste File file("some.txt");et c'est tout (non open, non close, non try...)
Matthieu M.

D a également RAII
Demi

@Demetri: Je ne connais pas trop D, pourriez-vous expliquer comment RAII interagit avec Garbage Collection? Je sais qu’en Python, vous pouvez écrire une méthode "deinit", mais la documentation vous avertit qu’en cas de cycle de références, certains objets ne verront pas leur méthode appelée appelée.
Matthieu M.

9

Une erreur courante qui correspond à vos critères est de ne pas comprendre le fonctionnement des constructeurs de copie s’agissant de la mémoire allouée dans votre classe. J'ai perdu le compte du temps que j'ai passé à réparer les crashs ou les fuites de mémoire parce qu'un "noob" a placé ses objets dans une carte ou un vecteur et n'a pas écrit correctement les constructeurs de copie et les destructeurs.

Malheureusement, le C ++ est plein de pièges "cachés" comme celui-ci. Mais se plaindre, c'est comme se plaindre de se rendre en France et de ne pas comprendre ce que les gens disaient. Si vous allez y aller, apprenez la langue.


1
Je pense que le problème avec C ++ est qu’il est très facile de se tirer une balle dans le pied. Bien sûr, il y a de bons programmeurs C ++, beaucoup de bons logiciels écrits en C ++. Mais il est très difficile de devenir un bon développeur C ++. La série "Efficient C ++" de Scott Meyers montre le nombre de subtilités du langage.
Marco Mustapic

Je suis d'accord. Une partie du problème réside cependant dans le fait que beaucoup (la majorité) des programmeurs C ++ pensent savoir ce qu’ils font alors qu’ils ne le savent pas. Voulez-vous dire "Effective C ++"?
Henry

Au moins, cela s’améliore avec les nouvelles règles plutôt restrictives sur la génération implicite d’opérations de copie / déplacement en C ++ 0x. Dans bon nombre des cas de violation de la règle des trois, la génération implicite d'opérations de copie sera obsolète et devrait générer un avertissement.
Sellibitze

6

C ++ permet une grande variété de fonctionnalités et de styles de programmation, mais cela ne signifie pas pour autant que ce sont de bonnes manières d'utiliser le C ++. Et en fait, il est incroyablement facile d'utiliser C ++ de manière incorrecte.

Il doit être appris et compris correctement , le simple fait d'apprendre en pratiquant (ou en l'utilisant comme si on utilisait un autre langage) conduirait à un code inefficace et source d'erreurs.


4

Eh bien ... Pour commencer, vous pouvez lire la FAQ Lite de C ++

Ensuite, plusieurs personnes ont construit des carrières en écrivant des livres sur les subtilités du C ++:

Herb Sutter et Scott Meyers, à savoir.

En ce qui concerne le discours de Torvalds qui manque de substance ... allez, sérieusement: personne n’a eu autant d’encre à parler de ses nuances. Vos livres Python & Ruby & Java se concentrent tous sur l’écriture d’applications ... vos livres C ++ traitent de fonctionnalités / conseils / pièges en langage idiot.


1
Hmm ... javapuzzlers.com , jimbrooks.org/web/python/#Pitfalls . Je dirais que le C ++ accéléré (pour un exemple) se concentre beaucoup plus sur la façon d'écrire du code que celui-ci ...
Jerry Coffin

1
Vous avez évoqué quelques exemples de ressources qui signalent des cas critiques dans leurs langues respectives. des choses qui semblent étranges et vous ne savez pas trop comment elles fonctionneraient (bien que la liste python soit proche) ... C ++ a toute une industrie qui indique des choses qui semblent parfaitement valides et se comportent de manière inattendue.
rouge-saleté

3

Des modèles trop lourds peuvent ne pas entraîner de bogues au début. Avec le temps, les utilisateurs devront modifier ce code et auront du mal à comprendre un énorme modèle. C'est alors que les bogues entrent - les incompréhensions provoquent des commentaires "Il compile et exécute", ce qui conduit souvent à un code presque correct mais pas tout à fait correct.

Généralement, si je me vois faire un modèle générique profond à trois niveaux, je m'arrête et pense à la façon dont il pourrait être réduit à un. Souvent, le problème est résolu en extrayant des fonctions ou des classes.


8
Conserver du code compliqué face aux exigences changeantes provoque toujours des bogues sans effort, rien de particulier à propos des modèles proposés.
Fred Nurk

2

Attention: ce n'est pas aussi une réponse qu'une critique de la conversation à laquelle "utilisateur inconnu" était associé dans sa réponse.

Son premier point principal est le (soi-disant) "standard en constante évolution". En réalité, les exemples qu'il cite tous concernent des modifications de C ++ avant la standardisation. Depuis 1998 (date à laquelle la première norme C ++ a été finalisée), les modifications apportées au langage ont été plutôt minimes. En fait, nombreux sont ceux qui affirment que le vrai problème est que davantage de modifications auraient dû être apportées. Je suis raisonnablement certain que tout le code conforme à la norme C ++ d'origine reste conforme à la norme actuelle. Bien que ce soit un peu moins certain, à moins que quelque chose ne change rapidement (et de façon tout à fait inattendue), il en ira de même pour le prochain standard C ++ (en théorie, tout le code utiliséexportva casser, mais pratiquement aucun n'existe; d’un point de vue pratique, ce n’est pas un problème). Je peux penser à quelques autres langages, systèmes d’exploitation (ou beaucoup d’autres éléments liés à l’informatique) pouvant prétendre à une telle affirmation.

Il se lance ensuite dans des "styles en constante évolution". Encore une fois, la plupart de ses points sont assez proches du non-sens. Il essaie de caractériser for (int i=0; i<n;i++)comme "vieux et éclaté" et for (int i(0); i!=n;++i)"nouvelle chaleur". La réalité est que, même s’il existe certains types pour lesquels de tels changements pourraient avoir un sens, intcela ne fait aucune différence - et même lorsque vous pouvez gagner quelque chose, il est rarement nécessaire de rédiger du code correct ou correct. Même au mieux, il fabrique une montagne à partir d'une taupinière.

Son affirmation suivante est que C ++ "optimise dans la mauvaise direction" - en particulier, alors qu'il admet que l'utilisation de bonnes bibliothèques est facile, il affirme que C ++ "rend l'écriture de bonnes bibliothèques presque impossible." Je pense que c’est l’une de ses erreurs les plus fondamentales. En réalité, écrire de bonnes bibliothèques pour presque toutes les langues est extrêmement difficile. Au minimum, écrire une bonne bibliothèque nécessite de bien comprendre un domaine problématique afin que votre code fonctionne pour une multitude d'applications possibles dans ce domaine (ou en relation avec celui-ci). La plupart de ce que C ++ fait réellement est de "relever le niveau" - après avoir constaté à quel point une bibliothèque peut être meilleure , les gens sont rarement disposés à revenir à écrire le genre de foutaises qu'ils auraient autrement.de très bons codeurs écrivent pas mal de bibliothèques, qui peuvent ensuite être utilisées (facilement, comme il le reconnaît) par "le reste d'entre nous". C'est vraiment un cas où "ce n'est pas un bug, c'est une fonctionnalité".

Je ne vais pas essayer de toucher chaque point dans l'ordre (cela prendrait des pages), mais aller directement à son point de clôture. Il cite Bjarne: "L'optimisation de tout un programme peut être utilisée pour éliminer les tables de fonctions virtuelles et les données RTTI inutilisées. Une telle analyse convient particulièrement aux programmes relativement petits qui n'utilisent pas de liaison dynamique."

Il critique cela en affirmant sans fondement que "c'est un problème vraiment difficile", allant même jusqu'à le comparer au problème de fond. En réalité, il n'en est rien - c'est l'éditeur de liens inclus dans Zortech C ++ (le premier compilateur C ++ pour MS-DOS dans les années 1980) qui l'a fait. Il est vrai qu’il est difficile d’être certain que toutes les données potentiellement superflues ont été éliminées, mais qu’il est tout à fait raisonnable de faire un travail plutôt équitable.

Indépendamment de cela, toutefois, le point le plus important est que cela n’est absolument pas pertinent pour la plupart des programmeurs. Comme le savent ceux d’entre nous qui ont désassemblé pas mal de code, à moins que vous n’écriviez un langage assembleur sans aucune bibliothèque, vos exécutables contiennent presque certainement une bonne quantité de «choses» (code et données, dans des cas typiques) que probablement pas même savoir, pour ne jamais mentionner réellement utiliser. Pour la plupart des gens, la plupart du temps, cela n'a pas d'importance - à moins que vous ne développiez des systèmes embarqués les plus minuscules, cette consommation de stockage supplémentaire n'a tout simplement pas d'importance.

En fin de compte, il est vrai que ce discours a un peu plus de substance que l'idiotie de Linus - mais cela lui donne exactement le poids de la louange qu'il mérite.


1

En tant que programmeur C qui a dû coder en C ++ à cause de circonstances inévitables, voici mon expérience. C’est très peu de choses que j’utilise, c’est le C ++ et la plupart du temps, c’est parce que je ne comprends pas très bien le C ++. Je n'avais / n'ai pas de mentor pour me montrer les subtilités du C ++ et comment écrire du bon code. Et sans l'aide d'un très bon code C ++, il est extrêmement difficile d'écrire un bon code en C ++. IMHO c'est le plus gros inconvénient de C ++ car il est difficile de trouver de bons codeurs C ++ prêts à prendre en main les débutants.

Certains des succès que j'ai vus sont généralement dus à l'allocation de mémoire magique de STL (oui, vous pouvez changer l'allocateur, mais qui le fait quand il commence avec C ++?). Vous entendez généralement les arguments des experts en C ++ selon lesquels les vecteurs et les tableaux offrent des performances similaires, car les vecteurs utilisent les tableaux en interne et que l'abstraction est extrêmement efficace. J'ai trouvé que cela était vrai dans la pratique pour l'accès vectoriel et la modification de valeurs existantes. Mais ce n'est pas vrai pour l'ajout d'une nouvelle entrée, la construction et la destruction de vecteurs. gprof a montré que, cumulativement, 25% du temps d'une application était consacré aux constructeurs de vecteurs, aux destructeurs, à memmove (déplacement d'un vecteur entier pour l'ajout d'un nouvel élément) et à d'autres opérateurs vectoriels surchargés (comme ++).

Dans la même application, le vecteur de quelque choseSmall a été utilisé pour représenter un quelque chose de grand. Il n'y avait pas besoin d'un accès aléatoire à quelque choseSmall dans quelque chose de Big. Encore un vecteur a été utilisé à la place d'une liste. La raison pour laquelle le vecteur a été utilisé? Parce que le codeur d'origine était familier avec la syntaxe de type tableau de vecteurs et pas très familier avec les itérateurs nécessaires aux listes (oui, il est issu d'un fond C). Cela prouve que beaucoup d’experts sont nécessaires pour maîtriser le C ++. C offre si peu de constructions de base, sans aucune abstraction, que vous pouvez l’obtenir plus facilement que C ++.



0

STL et boost sont portables, au niveau du code source. Je suppose que ce dont parle Linus, c’est que C ++ n’a pas d’ABI (interface binaire d’application). Vous devez donc compiler toutes les bibliothèques avec lesquelles vous êtes liés, avec la même version du compilateur et avec les mêmes commutateurs, sinon vous limiter à l’ABI C au niveau des bibliothèques de la DLL. Je trouve également que annyoing .. mais à moins de créer des bibliothèques tierces, vous devriez être capable de prendre le contrôle de votre environnement de construction. Je trouve que me limiter au C ABI ne vaut pas la peine. La commodité de pouvoir passer des chaînes, des vecteurs et des pointeurs intelligents d’une dll à une autre vaut la peine de reconstruire toutes les bibliothèques lors de la mise à niveau des compilateurs ou de la modification de leurs commutateurs. Les règles d'or que je suis sont les suivantes:

-Hériter de réutiliser l'interface, pas la mise en œuvre

-Préférencer l'agrégation sur l'héritage

-Préférer si possible des fonctions libres aux méthodes membres

-Toujours utiliser l'idiome RAII pour sécuriser fortement votre code. Évitez les prises.

-Utilisez les pointeurs intelligents, évitez les pointeurs nus (non possédés)

-Préférer la sémantique de valeur à la sémantique de référence

-Ne réinventez pas la roue, utilisez stl et boost

-Utilisez l'idiome Pimpl pour masquer les données privées et / ou pour fournir un pare-feu de compilation


-6

Ne pas mettre une finale ;à la fin d'une déclaration de clase, du moins dans certaines versions de VC.


4
C'est peut-être une erreur très courante pour les débutants (comme presque tout pour quelqu'un qui apprend encore la syntaxe de base), mais y a-t-il beaucoup de gens qui se disent compétents et qui trouvent encore cette erreur remarquable?
Fred Nurk

1
Je l’ai écrit juste parce que le compilateur vous a donné une erreur qui n’a rien à voir avec le manque de point-virgule.
Marco Mustapic

2
oui, exactement la même erreur est ce que vous obtenez d'un compilateur C.
Mircea Chirea
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.