28 votes

Dois-je encore utiliser les gardes #include ET #pragma une fois ?

enter image description here

http://en.wikipedia.org/wiki/Pragma_once
Dois-je encore utiliser les gardes d'inclusion quand tous ces compilateurs supportent #pragma once ?
Beaucoup de réponses sur stack overflow disent d'utiliser les deux pour la compatibilité, mais je ne suis pas sûr que cela soit toujours vrai. Quels compilateurs actuels ne supportent pas #pragma once ?

Je ne sais pas si l'utilisation des deux méthodes n'était qu'une recommandation avant qu'elle ne soit largement adoptée, ou s'il existe encore de très bonnes raisons d'utiliser les deux méthodes.
Des exemples de situations où l'on utilise seulement #pragma once causera des problèmes ?

11voto

Alok Save Points 115848

Cela dépend du degré de portabilité de votre programme.

Tant que vous écrivez un programme qui est censé fonctionner avec des compilateurs dont vous savez qu'ils supportent certainement #prama once en utilisant simplement #pragma once devrait suffire. Mais en faisant cela, vous limitez votre programme à l'ensemble des compilateurs qui supportent la fonctionnalité définie par l'implémentation.

Si vous voulez que votre programme fonctionne sur tous les compilateurs alors vous devez utiliser #pragma once et inclure les gardes à la fois.

Dans le cas où un compilateur ne supporte pas #pragma once il l'ignorera tout simplement [Ref#1] Dans ce cas, les gardes d'en-tête vous serviront, donc il n'y a rien de mal à les utiliser tous les deux lorsque vous n'êtes pas au courant des fonctionnalités supportées par vos compilateurs cibles.

Ainsi, si vous voulez que votre programme soit 100% portable sur différents compilateurs, l'idéal est encore d'utiliser uniquement les gardes d'inclusion. Comme @CharlesBailey le fait remarquer à juste titre, puisque le comportement de #pragma once est définie par l'implémentation, le comportement sur un compilateur inconnu pourrait avoir un effet néfaste sur votre programme.


[Ref#1]
Standard C++03 : 16.6 Directive Pragma

Une directive de prétraitement de la forme

# pragma pp-tokensopt new-line

fait en sorte que l'implémentation se comporte d'une manière définie par l'implémentation. Tout pragma qui n'est pas reconnu par l'implémentation est ignoré.

8voto

gvd Points 1057

Ce n'est pas standard, donc si vous voulez être sûr, utilisez les protections incluses.

4voto

PeterSW Points 1392

Comme le montre votre tableau, il est très rare aujourd'hui de rencontrer un compilateur en usage courant qui ne supporte pas #pragma once . Pour garder une base de code propre et peu coûteuse à maintenir, il faut un effort constant de refactoring. Devoir mettre à jour les gardes d'inclusion à chaque fois que vous renommez une classe ou déplacez du code ajoute une charge significative à cet effort.

Je dirais donc qu'à part quelques cas particuliers ou pour des systèmes de construction défectueux #pragma once est en pratique fiable. Si vous vous souciez de la productivité et de la qualité du code en utilisant seulement #pragma once semble être le choix évident.

Les exceptions étant si vous écrivez une bibliothèque qui doit supporter tous les compilateurs sous le soleil ou si vous avez la malchance de devoir travailler avec l'un de ces rares compilateurs qui ne possède pas cette fonctionnalité.

2voto

JBentley Points 3147

L'un des principaux avantages de #pragma once est qu'il peut accélérer les temps de compilation, lorsque vous incluez le même fichier d'en-tête plus d'une fois dans la même unité de traduction. Par exemple, si A.h comprend B.h y C.h y B.h comprend C.h alors le préprocesseur devra ouvrir et traiter C.h deux fois (au moins dans la mesure où vous évaluez votre #ifndef / #endif bloc), et #pragma once évitera ce problème car le préprocesseur peut ignorer complètement le fichier après la première inclusion.

Vous pouvez cependant obtenir le même effet en utilisant des gardes d'inclusion redondantes, par exemple :

C.h :

// Primary include guard:
#ifndef C_H
#define C_H

// code

#endif

B.h :

#ifndef B_H
#define B_H

// Secondary include guard:
#ifndef C_H
#include "C.h"
#endif

#endif

Cependant, vous avez toujours les autres inconvénients des gardes inclusifs, par exemple les conflits de noms, la maintenance supplémentaire et le risque de fautes de frappe, ainsi qu'un inconvénient supplémentaire, à savoir que B.h y C.h sont maintenant plus étroitement couplés (parce que B.h est maintenant conscient d'un détail de mise en œuvre dans C.h - a #define changement dans C.h qui n'affecte pas l'interface nécessitera la mise à jour de tous les fichiers qui l'incluent). Ce n'est généralement pas un problème car les protections d'inclusion sont généralement basées sur le nom du fichier, et un changement de nom de fichier aura le même effet de toute façon.

En utilisant cette technique, vous avez une raison de moins d'utiliser l'outil non portable #pragma once (comme expliqué dans les autres réponses).

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