255 votes

public statiques const vs #define

Est-il préférable d’utiliser vars que préprocesseur ? Ou peut-être que cela dépend du contexte ?

Quels sont les avantages/inconvénients de chaque méthode ?

264voto

Tony D Points 43962

Des avantages et des inconvénients à tout, en fonction de l'utilisation:

  • les enums
    • seulement possible pour les valeurs entières
    • correctement portée / l'identificateur de choc questions traitée très bien, en particulier en C++11 énumérer les classes où les énumérations pour enum class X sont analysées par le champ d'application X::
    • fortement typé, mais pour un grand-assez signé-ou-unsigned int taille sur laquelle vous n'avez aucun contrôle en C++03 (mais vous pouvez spécifier un champ de bits dans lequel ils doivent être emballés si l'enum est un membre de la struct/classe/de l'union), tandis que le C++11 par défaut est int mais peut être définie explicitement par le programmeur
    • ne peut pas prendre l'adresse - il n'y a pas que les valeurs d'énumération sont effectivement substitué incorporé à différents points d'utilisation
    • plus forte utilisation des dispositifs de retenue (par exemple, l'incrémentation - template <typename T> void f(T t) { cout << ++t; } ne compile pas, si vous pouvez l'envelopper d'un enum dans une classe implicite du constructeur, opérateur de coulée définies par l'utilisateur et les opérateurs)
    • chaque constante du type de prises de la enfermant enum, alors template <typename T> void f(T) obtenir un distinct lors de l'instanciation passé de la même valeur numérique à partir de différentes énumérations, qui sont distinctes de toute réelle f(int) de l'instanciation. Chaque fonction de l'objet du code pourrait être identiques (en ignorant l'adresse de compensations), mais je ne m'attends pas à un compilateur/linker pour éliminer l'inutile copies, si vous pouvez vérifier que votre compilateur/linker si vous vous souciez.
    • même avec typeof/decltype, ne peut pas s'attendre numeric_limits de fournir un aperçu utile de l'ensemble des valeurs significatives et les combinaisons (en effet, "juridique" combinaisons ne sont même pas écrites dans le code source, envisager enum { A = 1, B = 2 } - est - A|B "juridique" à partir d'une logique de programme en perspective?)
    • l'enum typename peut apparaître dans de nombreux endroits en RTTI, compilateur de messages, etc. - peut-être utile, éventuellement, de la dissimulation de l'
    • vous ne pouvez pas utiliser une énumération sans l'unité de traduction en train de voir la valeur, ce qui signifie que les énumérations dans la bibliothèque d'Api besoin les valeurs exposées dans l'en-tête, et make et d'autres timestamp à base de recompilation des outils de déclencher client recompilation lorsqu'ils sont modifiés (mauvais!)
  • consts
    • correctement portée / l'identificateur de choc questions traitées joliment
    • forte, unique, spécifié par l'utilisateur de type
      • vous essayez peut-être de "type" #define ala #define S std::string("abc"), mais la constante permet d'éviter que plusieurs de construction de différentes temporaires à chaque point d'utilisation
    • Une Définition de la Règle de complications
    • peut prendre de l'adresse, de créer const références etc.
    • plus semblable à une non-const de la valeur, qui minimise le travail et l'impact en cas de changement entre les deux
    • la valeur peut être placé à l'intérieur du fichier de mise en oeuvre, permettant localisée recompiler et simplement client liens pour ramasser le changement
  • définit
    • ""portée globale / plus sujettes à des conflits d'usages, qui peut produire difficiles à résoudre compilation des questions et de l'inattendu, de l'exécution et des résultats en temps plutôt que de sane messages d'erreur; atténuer ce qui implique:
      • long, obscur et/ou coordonnés de manière centralisée les identifiants, et l'accès à ceux-ci ne peut bénéficier de implicitement d'appariement utilisées/actuel/Koenig-consulté espace de noms, de noms d'alias etc.
      • alors que le détriment de meilleur-pratique permet paramètre de modèle identificateurs caractère unique des lettres majuscules (éventuellement suivi d'un nombre), de l'utilisation des identifiants sans lettres minuscules est traditionnellement réservée et attend de préprocesseur (à l'extérieur de l'OS et des bibliothèques C/C++ en-têtes). Ceci est important pour l'entreprise de préprocesseur utilisation à rester gérable. 3ème partie les bibliothèques peuvent être tenus de se conformer. En observant ce qui implique la migration de l'existant consts ou les énumérations vers/depuis définit implique un changement dans la capitalisation, et donc nécessite des modifications de client code source plutôt qu'un "simple" recompiler. (Personnellement, je mettre en majuscule la première lettre de énumérations, mais pas consts, alors j'aimerais être frappé de la migration entre ces deux trop - peut-être temps de repenser à ça.)
    • de plus au moment de la compilation des opérations possibles: chaîne de caractères littérale de concaténation, stringification (en prenant de la taille de celle-ci), la concaténation dans les identificateurs
      • inconvénient est que, compte tenu de #define X "x" et certains l'utilisation du client ala "pre" X "post", si vous voulez ou avez besoin de faire X à l'exécution variable variable plutôt qu'à une constante que vous vigueur des modifications de code client (plutôt que de simplement la recompilation), alors que la transition est plus facile à partir d'un const char* ou const std::string étant donné qu'ils ont déjà de la force à l'utilisateur d'intégrer la concaténation des opérations (par exemple, "pre" + X + "post" pour string)
    • ne pouvez pas utiliser sizeof directement définies littéral numérique
    • non typé (GCC ne pas avertir si comparé à d' unsigned)
    • certains compilateur/linker/débogueur chaînes ne peut présenter de l'identifiant, de sorte que vous serez réduit à regarder "nombres magiques" (cordes, etc...)
    • ne peut pas prendre l'adresse
    • la valeur substituée n'a pas besoin d'être juridique (ou discrètes) dans le contexte où le #define est créé, comme c'est évaluée à chaque point d'utilisation, de sorte que vous pouvez de référence qui n'est pas encore déclarée objets, dépendent de la "mise en œuvre" qui n'a pas besoin d'être pré-inclus, de créer des "constantes" comme { 1, 2 } qui peut être utilisée pour initialiser des tableaux, ou #define MICROSECONDS *1E-6 etc. (certainement ne la recommande pas!)
    • certaines des choses comme __FILE__ et __LINE__ peuvent être incorporés dans la substitution macro
    • vous pouvez tester l'existence et de la valeur en #if déclarations pour conditionnellement y compris le code (plus puissant qu'un post-prétraitement des "si" que le code n'a pas besoin d'être compilable si non sélectionné par le préprocesseur), utilisez #undef-ine, redéfinir etc.
    • texte substitué doit être exposé:
      • dans l'unité de traduction, elle est utilisée par, ce qui signifie que les macros dans les bibliothèques pour l'usage du client doit être dans l'en-tête, de sorte make et d'autres timestamp à base de recompilation des outils de déclencher client recompilation lorsqu'ils sont modifiés (mauvais!)
      • ou sur la ligne de commande, où encore plus d'attention est nécessaire pour que le code du client est recompilé (par exemple, le Makefile ou un script en fournissant la définition devrait être répertorié comme une dépendance)

En règle générale, j'utilise consts et d'en tenir compte le plus professionnel option pour utilisation générale (même si les autres sont d'une simplicité séduisante à ce vieux paresseux programmeur).

155voto

T.E.D. Points 26829

Personnellement, je hais le préprocesseur, alors je serais toujours aller avec const.

Le principal avantage d'un #define est qu'il ne nécessite pas de mémoire pour les stocker dans votre programme, car il est vraiment juste de remplacer un texte avec une valeur littérale. Il a aussi l'avantage qu'il n'a pas de type, de sorte qu'il peut être utilisé pour n'importe quelle valeur entière sans générer des avertissements.

Les avantages de "const"s qu'ils sont peut être portée, et ils peuvent être utilisés dans les situations où un pointeur vers un objet doit être passé.

Je ne sais pas exactement ce que vous obtenez avec la partie "statique". Si vous êtes déclarant globalement, je l'avais mis dans un anonomous espace de noms au lieu d'utiliser de l'électricité statique. Par exemple

namespace {
   unsigned const seconds_per_minute = 60;
};

int main (int argc; char *argv[]) {
...
}

50voto

AndreyT Points 139512

Si c'est un C++, et il mentionne #define comme une alternative, alors il est "global" (c'est à dire le fichier-champ) constantes, pas sur les membres de la classe. Quand il s'agit de ces constantes en C++ static const est redondante. En C++ const ont une liaison interne par défaut et il n'y a aucun point en déclarant static. Donc il est vraiment sur const vs #define.

Et, enfin, en C++ const est préférable. Au moins parce que ces constantes sont tapés et étendue. Il y a tout simplement pas de raisons de préférer #define sur const, en dehors de quelques exceptions près.

Constantes de chaîne, d'ailleurs, sont un exemple d'une telle exception. Avec #defined des constantes de chaîne, on peut utiliser au moment de la compilation de concaténation fonction de compilateurs C/C++, comme dans

#define OUT_NAME "output"
#define LOG_EXT ".log"
#define TEXT_EXT ".txt"

const char *const log_file_name = OUT_NAME LOG_EXT;
const char *const text_file_name = OUT_NAME TEXT_EXT;

P. S. Encore une fois, juste au cas où, si quelqu'un parle de static const comme une alternative à l' #define, cela signifie généralement qu'ils parlent C, pas du C++. Je me demande si cette question est correctement balisé...

5voto

JP. Points 858

À l’aide d’un public static const est similaire à l’utilisation de toutes les autres variables const dans votre code. Cela signifie que vous pouvez suivre partout où les informations proviennent, par opposition à un #define qui sera tout simplement remplacée dans le code dans le processus de précompilation.

Vous voudrez peut-être jeter un oeil à la C++ FAQ Lite pour cette question : http://www.parashift.com/c++-faq-lite/newbie.html#faq-29.7

5voto

RED SOFT ADAIR Points 5762
<ul> <li>Un public static const est typé (il possède le type) et peut être vérifié par le compilateur pour la validité, redéfinition etc..</li> <li>un #define peut être redéfinie indéfini quoi que.</li> </ul> <p>Habituellement, vous devez préférer consts statique. Il n’a aucun inconvénient. Le prprocessor principalement doit être utilisé que pour la compilation conditionnelle (et parfois pour les promos vraiment sale peut-être).</p>

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