75 votes

Quels pièges C++ dois-je éviter ?

Je me rappelle tout d’abord apprendre vecteurs dans la STL et après un certain temps, j’ai voulu utiliser un vecteur de bool pour l’un de mes projets. Après avoir vu un comportement étrange et fait quelques recherches, j’ai appris qu' qu'un vecteur de bool n'est pas vraiment un vecteur de bool.

Y a-t-il tout autres pièges courants à éviter en C++ ?

76voto

Brian Stewart Points 4553

Une courte liste pourrait être:

  • Éviter les fuites de mémoire par le biais de l'utilisation partagée des pointeurs pour gérer l'allocation de la mémoire et de nettoyage
  • Utilisez l' Acquisition de Ressources Est d'Initialisation (RAII) s'attacha à gérer les ressources de nettoyage - en particulier en présence d'exceptions
  • Éviter d'appeler des fonctions virtuelles dans les constructeurs
  • Employer minimaliste techniques de codage lorsque cela est possible - par exemple, la déclaration des variables uniquement lorsque cela est nécessaire, la portée des variables, et au début de la conception, si possible.
  • Vraiment comprendre la gestion des exceptions dans votre code - tant en ce qui concerne les exceptions de vous lancer, ainsi que ceux lancés par les classes que vous utilisez peut-être indirectement. Ceci est particulièrement important en présence de modèles.

RAII, partagé pointeurs et minimaliste de codage sont bien sûr pas spécifique au C++, mais ils aident à éviter les problèmes qui font fréquemment des cultures lors de l'élaboration de la langue.

Quelques excellents livres sur ce sujet sont:

  • Effective C++ - Scott Meyers
  • Plus Efficace C++ - Scott Meyers
  • C++ Normes De Codage - Sutter & Alexandrescu
  • C++ Faq - Cline

La lecture de ces livres m'a aidé plus que toute autre chose pour éviter le genre de pièges dont vous parlez.

52voto

Les pièges dans l'ordre décroissant de leur importance

Tout d'abord, vous devriez visiter le primé C++ FAQ de la Lumière. Il a beaucoup de bonnes réponses pour les pièges. Si vous avez d'autres questions, rendez - ##c++ sur irc.freenode.org dans la CEI. Nous sommes heureux de vous aider, si nous le pouvons. Remarque tous les pièges suivants sont à l'origine écrit. Ils ne sont pas simplement copié à partir de sources aléatoires.


supprimer[] sur le nouveau, delete sur new[]

Solution: Faire ci-dessus, les rendements à un comportement indéfini: Tout ce qui pourrait arriver. De comprendre votre code et ce qu'il fait, et toujours delete[] ce que vous new[], et delete ce que vous new, alors que ça n'arrivera pas.

Exception:

typedef T type[N]; T * pT = new type; delete[] pT;

Vous avez besoin d' delete[] même si vous new, puisque vous les nouvelles ed d'un tableau. Donc, si vous travaillez avec des typedef, prendre un soin particulier.


L'appel d'une fonction virtuelle dans un constructeur ou un destructeur

Solution: l'Appel d'une fonction virtuelle de ne pas appeler les fonctions de remplacement dans les classes dérivées. L'appel d'une fonction virtuelle pure dans un constructeur ou desctructor est un comportement indéfini.


Appelant delete ou delete[] sur un déjà supprimé pointeur

Solution: Affecter 0 à chaque pointeur de vous supprimer. Appelant delete ou delete[] sur un pointeur null ne fait rien.


En prenant le sizeof d'un pointeur, lorsque le nombre d'éléments d'un "tableau" est calculée.

Solution: Passer le nombre d'éléments à côté du pointeur lorsque vous avez besoin pour passer un tableau comme un pointeur dans une fonction. Utiliser la fonction proposée ici si vous prenez le sizeof d'un tableau qui est censé pour être vraiment un tableau.


L'utilisation d'un tableau comme s'il s'agissait d'un pointeur. Ainsi, à l'aide de T ** pour les deux dimensions de la matrice.

Solution: Voir ici pour expliquer pourquoi ils sont différents et la façon dont vous les manipulez.


Écriture d'une chaîne de caractères littérale: char * c = "hello"; *c = 'B';

Solution: Allouer un tableau qui est initialisé à partir des données de la chaîne littérale, alors vous pouvez écrire à:

char c[] = "hello"; *c = 'B';

Écriture d'une chaîne de caractères littérale est un comportement indéfini. De toute façon, le ci-dessus, la conversion d'une chaîne littérale char * est obsolète. Si les compilateurs ne sera probablement avertir si vous augmentez le niveau d'avertissement.


La création de ressources, puis oublier de les libérer quand quelque chose se déclenche.

Solution: Utiliser des pointeurs intelligents comme std::unique_ptr ou std::shared_ptr comme l'ont souligné d'autres réponses.


La modification d'un objet deux fois, comme dans cet exemple: i = ++i;

Solution: Le dessus qui était censé affecter à i la valeur de i+1. Mais ce qu'il fait n'est pas défini. Au lieu de l'incrémentation i et l'affectation du résultat, il change i sur le côté droit. Modification d'un objet entre deux séquence de points est un comportement indéfini. Séquence de points comprennent ||, &&, comma-operator, semicolon et entering a function (liste non exhaustive!). Modifiez le code suivant à la faire se comporter correctement: i = i + 1;


Divers Questions

Oublier de rincer les ruisseaux avant d'appeler une fonction de blocage comme sleep.

Solution: Vider le flux en streaming soit en std::endl au lieu de \n ou en appelant stream.flush();.


La déclaration d'une fonction au lieu d'une variable.

Solution: Le problème se pose parce que le compilateur interprète par exemple

Type t(other_type(value));

en fonction de la déclaration d'une fonction t de revenir Type et ayant un paramètre de type other_type qui est appelé value. Vous le résoudre en mettant des parenthèses autour du premier argument. Maintenant, vous obtenez une variable t de type Type:

Type t((other_type(value)));

L'appel de la fonction d'un objet qui n'est déclaré dans le courant de l'unité de traduction (.cpp le fichier).

Solution: La norme ne définit pas l'ordre de création des objets libres (à l'espace de noms de champ) définis dans les différentes unités de traduction. L'appel d'une fonction membre d'un objet pas encore construit est un comportement indéfini. Vous pouvez définir la fonction suivante dans l'objet de la traduction de l'unité et de l'appeler à partir d'autres:

House & getTheHouse() { static House h; return h; }

Qui permettrait de créer l'objet de la demande et de vous laisser avec un objet construit au moment de l'appel des fonctions.


La définition d'un modèle dans un sous - .cpp le fichier, alors qu'il est utilisé dans un autre .cpp le fichier.

Solution: Presque toujours, vous obtiendrez des erreurs comme undefined reference to .... Mettre tous les modèle de définitions dans un en-tête, de sorte que lorsque le compilateur est en les utilisant, il peut déjà produire le code nécessaire.


static_cast<Derived*>(base); si la base est un pointeur vers une classe de base virtuelle de Derived.

Solution: Une classe de base virtuelle est une base qui se produit une seule fois, même si elle est héritée plus d'une fois par les différentes classes indirectement dans un arbre d'héritage. Faire ci-dessus n'est pas autorisé par la Norme. Utilisation dynamic_cast pour le faire, et assurez-vous que votre classe de base est polymorphe.


dynamic_cast<Derived*>(ptr_to_base); si la base est non-polymorphe

Solution: Le standard ne permettent pas à une triste d'un pointeur ou d'une référence lorsque l'objet passé n'est pas polymorphe. Elle ou une de ses classes de base doit avoir une fonction virtuelle.


Faire de votre fonction qui accepte T const **

Solution: on peut penser que c'est plus sûr que d'utiliser T **, mais en réalité, il provoque des maux de tête aux personnes qui veulent passer T**: Le standard ne le permet pas. Il donne un exemple clair de pourquoi il est refusé:

int main() {
    char const c = 'c';
    char* pc;
    char const** pcc = &pc; //1: not allowed
    *pcc = &c;
    *pc = 'C'; //2: modifies a const object
}

Toujours accepter l' T const* const*; à la place.

Un autre (fermé) pièges thread sur le C++, donc les gens à la recherche pour eux de les trouver, est de Débordement de Pile question C++ pièges.

16voto

17 of 26 Points 15941

Certains doivent avoir des livres C++ qui vous aideront à éviter les pièges communs de C++ :

C++ efficace
C++ plus efficace
STL efficace

Le livre de STL efficace explique le vecteur de bool question  :)

12voto

0124816 Points 804

Brian a une grande liste : J’ajouterais « Toujours marque seul argument les constructeurs explicites (sauf dans les rares cas vous voulez coulée automatique). »

8voto

Avdi Points 13086

Pas vraiment un truc, mais une ligne directrice générale: vérifiez vos sources. C++ est un ancien de la langue, et il a beaucoup changé au fil des ans. Les meilleures pratiques ont changé avec elle, mais malheureusement il y a encore beaucoup d'informations là-bas. Il y a eu quelques très bon livre recommandations sur ici - je peux deuxième achat de chacun de Scott Meyers C++ livres. Se familiariser avec Boost et avec le codage des styles utilisés dans Boost - les gens impliqués dans ce projet sont à la fine pointe de C++ design.

Ne pas réinventer la roue. Se familiariser avec la STL et Boost, et l'utilisation de leurs installations, à chaque fois que possible, rouler votre propre. En particulier, l'utilisation de la STL chaînes et des collections à moins d'avoir une très, très bonne raison de ne pas. Apprendre à connaître auto_ptr et les pointeurs intelligents de Boost bibliothèque très bien, de comprendre les circonstances dans lesquelles chaque type de pointeur intelligent est destiné à être utilisé, et ensuite utiliser des pointeurs intelligents partout que vous pourriez avoir utilisé brut des pointeurs. Votre code sera tout aussi efficace et beaucoup moins sujettes à des fuites de mémoire.

Utilisation static_cast, dynamic_cast, const_cast, et reinterpret_cast au lieu de C-style jette. À la différence de C-style jette ils vous permettent de savoir si vous êtes vraiment se demander pour un autre type de fonte que vous pensez que vous demandez. Et ils se distinguent viisually, en avertissant le lecteur que d'un plâtre.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X