Pourriez-vous donner un exemple où static_assert(...)
('C ++ 11') résoudrait le problème en question avec élégance?
Je connais le run-time assert(...)
. Quand devrais-je préférer static_assert(...)
au régulier assert(...)
?
En outre, boost
il y a quelque chose qui s'appelle BOOST_STATIC_ASSERT
, est-ce la même chose que static_assert(...)
?
Réponses:
Du haut de ma tête...
En supposant que cela
SomeLibrary::Version
soit déclaré comme un const statique, plutôt que d'être#define
d (comme on pourrait s'y attendre dans une bibliothèque C ++).Contraste d'avoir à compiler en fait
SomeLibrary
et votre code, tout lien, et lancez l'exécutable seulement alors pour savoir que vous avez passé 30 minutes compilant une version incompatibleSomeLibrary
.@Arak, en réponse à votre commentaire: oui, vous pouvez vous
static_assert
asseoir n'importe où, à première vue:la source
static_assert
dans un contexte de non-exécution? Cela semble un très bel exemple :)static_assert
. Si la condition n'est pas connue avant l'exécution du programme, utilisezassert
.L'assertion statique est utilisée pour faire des assertions au moment de la compilation. Lorsque l'assertion statique échoue, le programme ne se compile tout simplement pas. Ceci est utile dans différentes situations, comme, par exemple, si vous implémentez une fonctionnalité par code qui dépend de manière critique d'un
unsigned int
objet ayant exactement 32 bits. Vous pouvez mettre une affirmation statique comme celle-cidans votre code. Sur une autre plate-forme, avec un
unsigned int
type de taille différente, la compilation échouera, attirant ainsi l'attention du développeur sur la partie problématique du code et lui conseillant de le réimplémenter ou de le réinspecter.Pour un autre exemple, vous voudrez peut-être passer une valeur intégrale en tant que
void *
pointeur vers une fonction (un hack, mais parfois utile) et vous voulez vous assurer que la valeur intégrale tiendra dans le pointeurVous souhaiterez peut-être que l'élément dont le
char
type est signéou cette division intégrale avec des valeurs négatives arrondit vers zéro
Etc.
Dans de nombreux cas, les assertions d'exécution peuvent être utilisées à la place des assertions statiques, mais les assertions d'exécution ne fonctionnent qu'au moment de l'exécution et uniquement lorsque le contrôle passe sur l'assertion. Pour cette raison, une assertion d'exécution défaillante peut rester inactive, non détectée pendant de longues périodes.
Bien sûr, l'expression dans l'assertion statique doit être une constante au moment de la compilation. Il ne peut pas s'agir d'une valeur d'exécution. Pour les valeurs d'exécution, vous n'avez pas d'autre choix que d'utiliser l'ordinaire
assert
.la source
static_assert
spécifiquement à C ++ 11. Monstatic_assert
ci-dessus est juste une implémentation abstraite de l'assertion statique. (J'utilise personnellement quelque chose comme ça dans le code C). Ma réponse est destinée à concerner l'objectif général des assertions statiques et leur différence par rapport aux assertions d'exécution.unsigned int
. Ceci n'est pas garanti par la norme. Une variable de typeunsigned int
pourrait légalement occuper 32 bits de mémoire, laissant 16 d'entre eux inutilisés (et ainsi la macroUINT_MAX
serait égale à65535
). Ainsi, la façon dont vous décrivez la première assertion statique ("unsigned int
objet ayant exactement 32 bits") est trompeuse. Pour correspondre à votre description, cette affirmation doit être incluse ainsi:static_assert(UINT_MAX >= 0xFFFFFFFFu)
.Je l'utilise pour m'assurer que mes hypothèses sur le comportement du compilateur, les en-têtes, les bibliothèques et même mon propre code sont correctes. Par exemple ici, je vérifie que la structure a été correctement compressée à la taille attendue.
Dans un emballage de classe
stdio.h
« sfseek()
je, pris des raccourcis avecenum Origin
et vérifier que ces raccourcis sont alignés avec les constantes définies parstdio.h
Vous devriez préférer
static_assert
auassert
moment où le comportement est défini au moment de la compilation, et non au moment de l'exécution, comme les exemples que j'ai donnés ci-dessus. Un exemple où ce n'est pas le cas inclurait la vérification des paramètres et du code de retour.BOOST_STATIC_ASSERT
est une macro pré-C ++ 0x qui génère du code non conforme si la condition n'est pas satisfaite. Les intentions sont les mêmes, bien questatic_assert
standardisées et peuvent fournir de meilleurs diagnostics du compilateur.la source
BOOST_STATIC_ASSERT
est un wrapper multi-plateforme pour lastatic_assert
fonctionnalité.Actuellement, j'utilise static_assert pour appliquer des "Concepts" à une classe.
exemple:
Cela provoquera une erreur de compilation si l'une des conditions ci-dessus n'est pas remplie.
la source
Une utilisation de
static_assert
peut être de s'assurer qu'une structure (c'est-à-dire une interface avec le monde extérieur, comme un réseau ou un fichier) est exactement de la taille que vous attendez. Cela attraperait les cas où quelqu'un ajoute ou modifie un membre de la structure sans se rendre compte des conséquences. Lestatic_assert
ramasserait et alerterait l'utilisateur.la source
En l'absence de concepts, on peut utiliser
static_assert
pour une vérification de type simple et lisible à la compilation, par exemple, dans les modèles:la source
Cela ne répond pas directement à la question d'origine, mais constitue une étude intéressante sur la façon d'appliquer ces vérifications de temps de compilation avant C ++ 11.
Le chapitre 2 (section 2.1) de Modern C ++ Design par Andrei Alexanderscu implémente cette idée d'assertions au moment de la compilation comme ceci
Comparez la macro STATIC_CHECK () et static_assert ()
la source
Le
static_assert
peut être utilisé pour interdire l'utilisation dudelete
mot-clé de cette façon:#define delete static_assert(0, "The keyword \"delete\" is forbidden.");
Chaque développeur C ++ moderne voudra peut-être le faire s'il souhaite utiliser un garbage collector conservateur en utilisant uniquement les classes es et struct s qui surchargent l' opérateur new pour appeler une fonction qui alloue de la mémoire sur le tas conservateur du garbage collector conservateur qui peut être initialisé et instancié en invoquant une fonction qui fait cela au début de la
main
fonction.Par exemple, chaque développeur C ++ moderne qui souhaite utiliser le garbage collector conservateur Boehm-Demers-Weiser écrira au début de la
main
fonction:GC_init();
Et dans chaque
class
etstruct
surcharge deoperator new
cette façon:Et maintenant que le
operator delete
n'est plus nécessaire, parce que le garbage collector conservateur de Boehm-Demers-Weiser est responsable à la fois de libérer et de désallouer chaque bloc de mémoire lorsqu'il n'est plus nécessaire, le développeur veut interdire ledelete
mot - clé.Une façon est de surcharger de
delete operator
cette façon:Mais ce n'est pas recommandé, car le développeur C ++ moderne saura qu'il / elle a invoqué par erreur
delete operator
le temps d'exécution, mais il est préférable de le savoir bientôt au moment de la compilation.Donc, la meilleure solution à ce scénario à mon avis est d'utiliser le
static_assert
comme indiqué au début de cette réponse.Bien sûr, cela peut également être fait avec
BOOST_STATIC_ASSERT
, mais je pense questatic_assert
c'est mieux et que cela devrait toujours être préféré.la source