Assertions

Une instruction d'assertion spécifie une condition que vous vous attendez à ce que soit la valeur true à un point dans votre programme.Si cette condition n'est pas remplie, l'assertion échoue, l'exécution de votre programme est interrompue, et Boîte de dialogue d'assertion s'affiche.

Visual C++ prend en charge les instructions d'assertion basées sur les éléments suivants :

  • Les assertions MFC pour les programmes MFC.

  • ATLASSERT pour les programmes qui utilisent ATL ;

  • assertions CRT pour les programmes qui utilisent la bibliothèque Runtime C ;

  • la fonction d'assertion ANSI pour les autres programmes C/C++.

Vous pouvez utiliser des assertions pour intercepter les erreurs de logique, contrôler les résultats d'une opération, et des conditions d'erreur de test qui devraient avoir été gérées.

Dans cette rubrique

Comment les assertions fonctionnent

Les assertions debug et les versions release

Effets secondaires d'utiliser des assertions

Assertions CRT

Les assertions MFC

  • MFC ASSERT_VALID et CObject::AssertValid

  • Limites de la fonction AssertValid

Utilisation des assertions

  • Interception des erreurs de logique

  • Contrôle des résultats

  • Rechercher des erreurs non gérées

Comment les assertions fonctionnent

Lorsque le débogueur s'arrête en raison de MFC ou assertion de la bibliothèque Runtime C, alors que la source est disponible, le débogueur parcourt le débogage dans le fichier source où l'assertion a eu lieu.Le message d'assertion apparaît dans Fenêtre Sortie et la boîte de dialogue Échec de l'assertion .Vous pouvez copier le message d'assertion de la fenêtre Sortie dans une fenêtre texte si vous voulez l'enregistrer pour vous y référer ultérieurement.La fenêtre Sortie peut également contenir d'autres messages d'erreur.Examinez attentivement ces messages, car ils fournissent des indications sur la cause de l'échec de l'assertion.

Assertions de utilisation pour détecter des erreurs pendant le développement.En règle générale, utilisez une assertion pour chaque hypothèse.Par exemple, si vous supposez qu'un argument n'est pas nul, utilisez une assertion pour tester cette hypothèse.

Dans cette rubrique

Les assertions debug et les versions release

Les instructions d'assertion compilent uniquement si _DEBUG est défini.Sinon, le compilateur traite des assertions comme instructions null.Par conséquent, les instructions d'assertion n'imposent pas de charge ou coût de performance dans votre programme de la version finale, et vous permettent d'éviter d'utiliser des directives d' #ifdef .

Effets secondaires d'utiliser des assertions

Lorsque vous ajoutez des assertions à votre code, assurez-vous qu'elles n'ont pas d'effets secondaires.Par exemple, considérez l'assertion suivante qui modifie la valeur d' nM :

ASSERT(nM++ > 0); // Don't do this!

Étant donné que l'expression d' ASSERT n'est pas évaluée dans la version Release de votre programme, nM aura des valeurs différentes dans le débogage et les versions Release.Pour éviter ce problème dans MFC, vous pouvez utiliser la macro dans VÉRIFIEZ au lieu d' ASSERT.VERIFY évalue l'expression dans toutes les versions mais ne vérifie pas le résultat dans la version Release.

Soyez particulièrement vigilant avec les appels aux fonctions à l'intérieur des instructions d'assertion ; l'évaluation d'une fonction peut avoir des effets secondaires inattendus.

ASSERT ( myFnctn(0)==1 ) // unsafe if myFnctn has side effects
VERIFY ( myFnctn(0)==1 ) // safe

VERIFY appelle myFnctn dans les versions debug versions debug et Release, il est acceptable de l'utiliser.Toutefois, l'utilisation VERIFY applique la charge d'un appel de fonction inutile dans la version Release.

Dans cette rubrique

Assertions CRT

Le fichier d'en-tête CRTDBG.H définit les macros ASSERT et ASSERTE pour la vérification des assertions.

Macro

Résultat

_ASSERT

Si l'expression spécifiée prend la valeur FALSE, nom de fichier et numéro de ligne de la macro _ASSERT.

_ASSERTE

Identique au résultat de _ASSERT, avec en plus une représentation sous forme de chaîne de l'expression qui a fait l'objet de l'assertion.

La macro _ASSERTE est plus puissante, car elle indique l'expression affirmée dont la valeur est FALSE.Cela peut être suffisant pour identifier le problème dans se reporter au code source.Néanmoins, la version Debug de votre application contiendra une constante de chaîne pour chaque expression affirmée avec _ASSERTE.Si vous utilisez de nombreuses macros _ASSERTE, ces expressions de chaîne occupent une quantité de mémoire considérable.Si cela pose un problème, utilisez _ASSERT pour économiser de la mémoire.

Lorsque _DEBUG est défini, le d' _ASSERTE est définie comme suit :

#define _ASSERTE(expr) \
   do { \
      if (!(expr) && (1 == _CrtDbgReport( \
         _CRT_ASSERT, __FILE__, __LINE__, #expr))) \
         _CrtDbgBreak(); \
   } while (0)

Si l'expression affirmée prend la valeur FALSE, _CrtDbgReport est appelé pour signaler l'échec de l'assertion (à l'aide d'une boîte de dialogue de message par défaut).Si vous choisissez Réessayer dans la boîte de dialogue de message, _CrtDbgReport retourne 1 et _CrtDbgBreak appelle le débogueur à DebugBreak.

ww5t02fa.collapse_all(fr-fr,VS.110).gifVérification de l'altération du tas

L'exemple suivant utilise _CrtCheckMemory pour vérifier l'altération du tas :

_ASSERTE(_CrtCheckMemory());

ww5t02fa.collapse_all(fr-fr,VS.110).gifVérification de la validité du pointeur

L'exemple suivant utilise _CrtIsValidPointer pour vérifier qu'une plage mémoire donnée est valide pour lire ou écrire.

_ASSERTE(_CrtIsValidPointer( address, size, TRUE );

L'exemple suivant utilise _CrtIsValidHeapPointer pour vérifier qu'un pointeur désigne la mémoire dans le tas local (le tas créé et managé par cette instance de la bibliothèque Runtime C — une DLL peut avoir sa propre instance de la bibliothèque et donc son propre tas, en dehors de celui de l'application).Cette assertion intercepte non seulement les adresses null ou hors limites, mais également les pointeurs vers des variables static, des variables stack et toute autre mémoire non locale.

_ASSERTE(_CrtIsValidPointer( myData );

ww5t02fa.collapse_all(fr-fr,VS.110).gifVérification d'un bloc de mémoire

L'exemple suivant utilise _CrtIsMemoryBlock pour vérifier qu'un bloc de mémoire se trouve dans le tas local et que son type est valide.

_ASSERTE(_CrtIsMemoryBlock (myData, size, &requestNumber, &filename, &linenumber));

Dans cette rubrique

Les assertions MFC

Les MFC définissent la macro ASSERT pour vérifier les assertions.Il définit également les méthodes d' MFC ASSERT_VALID et d' CObject::AssertValid pour contrôler l'état interne d' CObjectobjet dérivé.

Si l'argument de la macro MFC ASSERT la valeur zéro ou false, la macro arrête l'exécution du programme et avertit l'utilisateur ; sinon, l'exécution continue.

Lorsqu'une assertion échoue, une boîte de dialogue de message affiche le nom du fichier source et du numéro de la ligne de l'assertion.Si vous choisissez Réessayer dans la boîte de dialogue, un appel à AfxDebugBreak provoque un arrêt de l'exécution pour le débogueur.À ce stade, vous pouvez examiner la pile des appels et utiliser d'autres fonctionnalités de débogage pour déterminer pourquoi l'assertion a échoué.Si vous avez activé Débogage juste-à-temps, et le débogueur ne s'exécutait pas déjà, la boîte de dialogue peut lancer le débogueur.

L'exemple suivant montre comment utiliser ASSERT pour vérifier la valeur de retour d'une fonction :

int x = SomeFunc(y);
ASSERT(x >= 0);   //  Assertion fails if x is negative

Vous pouvez utiliser ASSERT avec la fonction IsKindOf pour vérifier les types des arguments d'une fonction :

ASSERT( pObject1->IsKindOf( RUNTIME_CLASS( CPerson ) ) );

Le d' ASSERT ne produit aucun code dans la version Release.Si vous avez besoin d'évaluer l'expression dans la version Release, utilisez la macro VERIFY à la place de la macro ASSERT.

ww5t02fa.collapse_all(fr-fr,VS.110).gifMFC ASSERT_VALID et CObject::AssertValid

La méthode CObject::AssertValid fournit des contrôles à l'exécution de l'état interne d'un objet.Bien que vous ne soyez pas tenus de substituer AssertValid lorsque vous dérivez votre classe de CObject, vous pouvez rendre votre classe plus fiable en effectuant cette opération.AssertValid doit exécuter des assertions sur les variables membres de tous les objets pour vérifier qu'elles contiennent des valeurs valides.Par exemple, elle vérifie en principe que les variables de membre de pointeur ne sont pas NULL.

L'exemple suivant montre comment déclarer une fonction AssertValid :

class CPerson : public CObject
{
protected:
    CString m_strName;
    float   m_salary;
public:
#ifdef _DEBUG
    // Override
    virtual void AssertValid() const;
#endif
    // ...
};

Lorsque vous substituez AssertValid, appelez la version de AssertValid correspondant à la classe de base avant d'effectuer vos propres vérifications.Utilisez ensuite la macro ASSERT pour vérifier les membres propres à votre classe dérivée, comme indiqué ci-après :

#ifdef _DEBUG
void CPerson::AssertValid() const
{
    // Call inherited AssertValid first.
    CObject::AssertValid();

    // Check CPerson members...
    // Must have a name.
    ASSERT( !m_strName.IsEmpty());
    // Must have an income.
    ASSERT( m_salary > 0 );
}
#endif

Si l'une de vos variables de membre stocke des objets, vous pouvez utiliser la macro ASSERT_VALID pour tester leur validité interne (si leurs classes substituent AssertValid).

Prenez, par exemple, une classe CMyData, qui stocke un CObList dans l'une de ses variables de membre.La variable CObList, m_DataList, stocke une collection d'objets CPerson.Une déclaration abrégée de CMyData a l'aspect suivant :

class CMyData : public CObject
{
    // Constructor and other members ...
    protected:
        CObList* m_pDataList;
    // Other declarations ...
    public:
#ifdef _DEBUG
        // Override:
        virtual void AssertValid( ) const;
#endif
    // And so on ...
};

La substitution de AssertValid dans CMyData a l'aspect suivant :

#ifdef _DEBUG
void CMyData::AssertValid( ) const
{
    // Call inherited AssertValid.
    CObject::AssertValid( );
    // Check validity of CMyData members.
    ASSERT_VALID( m_pDataList );
    // ...
}
#endif

CMyData utilise le mécanisme AssertValid pour tester la validité des objets stockés dans ses données membres.L'AssertValid de substitution dans CMyData appelle la macro ASSERT_VALID pour sa propre variable de membre m_pDataList.

Les tests de validité ne s'arrête pas à ce niveau que la classe CObList substitue également AssertValid.Cette substitution réalise des tests de validité supplémentaires sur l'état interne de la liste.Ainsi, un test de validité sur un objet CMyData conduit à des tests de validité supplémentaires pour contrôler les états internes de l'objet liste CObList stocké.

Moyennant un peu plus de travail, vous pourriez également ajouter des tests de validité pour les objets CPerson stockés dans la liste.Vous pourriez dériver une classe CPersonList de CObList et substituer AssertValid.Dans la substitution, vous appelleriez CObject::AssertValid, puis itéreriez au sein de la liste, en appelant AssertValid sur chaque objet CPerson stocké dans la liste.La classe CPerson affichée au début de cette rubrique substitue la fonction AssertValid.

Il s'agit d'un mécanisme puissant lorsque vous générez pour le débogage.Lorsque, par la suite, vous déboguez pour la diffusion, le mécanisme est automatiquement désactivé.

ww5t02fa.collapse_all(fr-fr,VS.110).gifLimites de la fonction AssertValid

Une assertion déclenchée indique que l'objet est manifestement défectueux et que l'exécution s'arrêtera.Toutefois, un échec d'assertion indique qu'aucun problème n'a été trouvé, mais l'objet n'est pas garanti être bon.

Dans cette rubrique

Utilisation des assertions

ww5t02fa.collapse_all(fr-fr,VS.110).gifInterception des erreurs de logique

Vous pouvez définir une assertion sur une condition qui doit être vraie en fonction de la logique de votre programme.L'assertion n'a aucun effet, sauf si une erreur de logique survient.

Par exemple, supposons que vous simulez des molécules de gaz dans un récipient et que la variable numMols représente le nombre total de molécules.Ce nombre ne peut pas être inférieur à zéro ; vous pourriez donc inclure une instruction d'assertion MFC, telle que :

ASSERT(numMols >= 0);

ou une assertion CRT, telle que :

_ASSERT(numMols >= 0);

Ces instructions restent inactives tant que votre programme fonctionne correctement.Si une erreur de logique provoque numMolsêtre inférieur à zéro, toutefois, l'assertion interrompt l'exécution de votre programme et affiche Échec de l'assertion, boîte de dialogue.

Dans cette rubrique

ww5t02fa.collapse_all(fr-fr,VS.110).gifContrôle des résultats

Les assertions sont valeur pour tester les opérations dont les résultats ne sont pas évidents d'une inspection visuelle rapide.

Considérons, par exemple, le code suivant, qui met à jour la variable iMols en fonction du contenu de la liste liée désignée par mols :

/* This code assumes that type has overloaded the != operator
 with const char * 
It also assumes that H2O is somewhere in that linked list. 
Otherwise we'll get an access violation... */
while (mols->type != "H2O")
{
 iMols += mols->num;
 mols = mols->next;
}
ASSERT(iMols<=numMols); // MFC version
_ASSERT(iMols<=numMols); // CRT version

Le nombre de molécules calculé par iMols doit toujours être inférieur ou égal au nombre total de molécules, numMols.Une inspection visuelle de la boucle ne montre pas que ce sera nécessairement le cas ; une instruction d'assertion est donc utilisée après la boucle pour tester cette condition.

Dans cette rubrique

ww5t02fa.collapse_all(fr-fr,VS.110).gifRechercher des erreurs non gérées

Vous pouvez utiliser des assertions pour tester les conditions d'erreur en un point de votre code où toutes les erreurs devraient avoir été gérées.Dans l'exemple suivant, une routine graphique retourne un code d'erreur ou zéro en cas de succès.

myErr = myGraphRoutine(a, b);

/* Code to handle errors and
   reset myErr if successful */

ASSERT(!myErr); -- MFC version
_ASSERT(!myErr); -- CRT version

Si le code de gestion des erreurs fonctionne correctement, l'erreur devrait être gérée et myErr réinitialisé avant que l'assertion ne soit atteinte.Si myErr a une autre valeur, l'assertion échoue, le programme s'arrête et la Échec de l'assertion, boîte de dialogue apparaît.

Les instructions d'assertion, toutefois, ne remplacent pas le code de gestion des erreurs.L'exemple suivant illustre une instruction d'assertion qui peut provoquer des problèmes dans le code de la version finale :

myErr = myGraphRoutine(a, b);

/* No Code to handle errors */

ASSERT(!myErr); // Don't do this!
_ASSERT(!myErr); // Don't do this, either!

Ce code s'appuie sur l'instruction d'assertion pour gérer la condition d'erreur.Par conséquent, tout code d'erreur retourné par myGraphRoutine sera non géré dans le code de la version finale.

Dans cette rubrique

Voir aussi

Référence

Assertions dans du code managé

Concepts

Sécurité du débogueur

Autres ressources

Débogage du code natif