Compartir a través de


Aserciones

Una instrucción de aserción especifica una condición que se espera que sea true en un punto del programa.Si la condición no es true, la aserción, la ejecución del programa se interrumpe, y El cuadro de diálogo error de aserción aparece.

Visual C++ admite las instrucciones de aserción basados en las construcciones siguientes:

  • Aserciones de MFC para programas MFC.

  • ATLASSERT para programas que utilizan ATL.

  • Aserciones de CRT para programas que utilizan la biblioteca en tiempo de ejecución de C.

  • La función assert de ANSI para otros programas en C o C++.

Puede utilizar aserciones para detectar los errores lógicos, comprobar resultados de una operación, y las condiciones de error de la prueba que deberían haberse controlado.

En este tema

Cómo funcionan las aserciones

Aserciones en las compilaciones de depuración y de lanzamiento

Efectos secundarios de utilizar aserciones

Aserciones de CRT

Aserciones de MFC

  • MFC ASSERT_VALID y CObject::AssertValid

  • Limitaciones de AssertValid

Mediante aserciones

  • Errores lógicos de detección

  • Comprobar los resultados

  • Buscar errores no controlados

Cómo funcionan las aserciones

Cuando el depurador se detiene debido a MFC o aserción de la biblioteca en tiempo de ejecución de C, después si el origen está disponible, el depurador navega hasta el punto en el archivo de código fuente donde la aserción.El mensaje de aserción aparece en Ventana de salida y el cuadro de diálogo Error de aserción .El mensaje de aserción se puede copiar desde la Ventana de salida en una ventana de texto si se desea guardarlo para consultas posteriores.La Ventana de salida puede contener también otros mensajes de error.Examine estos mensajes con cuidado, ya que pueden proporcionar pistas para encontrar la causa del error de aserción.

Aserciones de uso para detectar errores durante el desarrollo.En general, utilice una aserción para cada suposición.Por ejemplo, si supone que un argumento no es NULL, utilice una aserción para probar esa suposición.

En este tema

Aserciones en las compilaciones de depuración y de lanzamiento

Las instrucciones de aserción compilan sólo si se define _DEBUG .Si no, el compilador trata las aserciones como instrucciones null.Por consiguiente, las instrucciones de aserción no impone ninguna sobrecarga o el rendimiento costó en el programa de inicio final, y permite evitar utilizar las directivas de #ifdef .

Efectos secundarios de utilizar aserciones

Cuando agregue aserciones al código, asegúrese de que no producen efectos secundarios.Por ejemplo, considere la siguiente aserción que modifique el valor de nM :

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

Dado que la expresión de ASSERT no se evalúa en la versión de lanzamiento del programa, nM tendrá valores diferentes en las versiones de depuración y de lanzamiento.Para evitar este problema en MFC, puede utilizar la macro de COMPRUEBE en lugar de ASSERT.VERIFY evalúa la expresión en todas las versiones pero no comprueba el resultado en la versión de lanzamiento.

Tenga especial cuidado al utilizar llamadas a funciones en las instrucciones de aserción, ya que la evaluación de una función puede producir efectos laterales inesperados.

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

VERIFY llama myFnctn en las versiones de depuración y lanzamiento, de modo que puede utilizar.Sin embargo, mediante VERIFY impone la sobrecarga de una llamada de función innecesaria en la versión de lanzamiento.

En este tema

Aserciones de CRT

El archivo de encabezado CRTDBG.H define las macros _ASSERT y _ASSERTE para la comprobación de aserciones.

Macro

Resultado

_ASSERT

Si la expresión especificada se evalúa como FALSE, el resultado es el nombre de archivo y el número de línea de la expresión sometida a _ASSERT.

_ASSERTE

Igual que _ASSERT, más una representación de cadena de la expresión sometida a aserción.

_ASSERTE es más eficaz, ya que informa de la expresión sometida a aserción que resultó ser falsa (valor FALSE).Esto puede ser suficiente para identificar el problema sin consultar el código fuente.No obstante, la versión de depuración de la aplicación contiene una constante de tipo cadena para cada expresión sometida a aserción mediante _ASSERTE.Si se utilizan muchas macros _ASSERTE, estas expresiones de cadena ocupan una cantidad de memoria significativa.Si eso constituye un problema, utilice _ASSERT para ahorrar memoria.

Cuando se define _DEBUG , la macro se define de _ASSERTE como sigue:

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

Si la expresión sometida a aserción se evalúa como FALSE, se realiza una llamada a _CrtDbgReport para informar del error de aserción (mediante un cuadro de diálogo de mensaje, de forma predeterminada).Si elige Reintentar en el cuadro de mensaje, _CrtDbgReport devuelve 1 y _CrtDbgBreak llama el depurador con DebugBreak.

ww5t02fa.collapse_all(es-es,VS.110).gifComprobar si el montón está dañado

El siguiente ejemplo usa _CrtCheckMemory para comprobar si el montón ha sufrido algún daño:

_ASSERTE(_CrtCheckMemory());

ww5t02fa.collapse_all(es-es,VS.110).gifComprobar la validez de los punteros

El siguiente ejemplo usa _CrtIsValidPointer para comprobar si un determinado intervalo de memoria es válido para lectura o escritura.

_ASSERTE(_CrtIsValidPointer( address, size, TRUE );

El siguiente ejemplo utiliza _CrtIsValidHeapPointer para comprobar si un puntero apunta a la memoria del montón local, que es el montón creado y administrado por esta instancia de la biblioteca en tiempo de ejecución de C (una DLL puede tener su propia instancia de la biblioteca y, por tanto, su propio montón, independiente del montón de la aplicación).Esta aserción captura no sólo direcciones null o fuera de límites, sino también punteros a variables estáticas, variables de pila y cualquier otra memoria no local.

_ASSERTE(_CrtIsValidPointer( myData );

ww5t02fa.collapse_all(es-es,VS.110).gifComprobar un bloque de memoria

El siguiente ejemplo utiliza _CrtIsMemoryBlock para comprobar si un bloque de memoria se encuentra en el montón local y tiene un tipo de bloque válido.

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

En este tema

Aserciones de MFC

MFC define la macro ASSERT para comprobar aserciones.También define los métodos de MFC ASSERT_VALID y de CObject::AssertValid para comprobar el estado interno de CObject- objeto derivado.

Si el argumento de la macro de MFC ASSERT se evalúa como cero o en false, la macro detiene la ejecución de un programa y alerta al usuario; si no, la ejecución continúa.

Cuando se produce un error de aserción, un cuadro de mensaje muestra el nombre del archivo de código fuente y el número de línea de la aserción.Si se elige Reintentar en el cuadro de diálogo, una llamada a AfxDebugBreak hace que la ejecución se interrumpa y se inicie el depurador.En ese momento, puede examinar la pila de llamadas y utilizar otros servicios del depurador para determinar el error de aserción.Si ha habilitado Depuración Just-In-Time, y el depurador no estaba ejecutando ya, el cuadro de diálogo puede iniciar el depurador.

El ejemplo siguiente se muestra cómo utilizar ASSERT para comprobar el valor devuelto de una función:

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

Se puede utilizar ASSERT con la función IsKindOf para proporcionar la comprobación de tipos de los argumentos de una función:

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

La macro de ASSERT no muestra ningún código de la versión de lanzamiento.Si necesita evaluar la expresión en la versión de lanzamiento, utilice la macro VERIFY en vez de ASSERT.

ww5t02fa.collapse_all(es-es,VS.110).gifMFC ASSERT_VALID y CObject::AssertValid

El método CObject::AssertValid proporciona comprobaciones en tiempo de ejecución del estado interno de un objeto .Aunque no es obligatorio reemplazar AssertValid al derivar la clase de CObject, puede conseguir una clase más confiable si lo hace.AssertValid debe realizar aserciones en las variables miembro del objeto para comprobar que contienen valores válidos.Por ejemplo, debería comprobar que las variables miembro no sean NULL.

En el ejemplo siguiente, se muestra cómo declarar una función AssertValid:

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

Cuando invalide AssertValid, llame a la versión de la clase base de AssertValid antes de ejecutar sus propias comprobaciones.Después, use la macro ASSERT para comprobar los miembros únicos de la clase derivada, como se muestra a continuación:

#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 cualquiera de las variables miembro almacenan objetos, se puede utilizar la macro ASSERT_VALID para probar su validez interna (si sus clases reemplazan la función AssertValid).

Por ejemplo, considere una clase CMyData, la cual almacena un objeto CObList en una de sus variables miembro.La variable CObList, m_DataList, almacena una colección de objetos CPerson.Una declaración abreviada de CMyData tiene el siguiente aspecto:

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 ...
};

El sustituto de AssertValid en CMyData es:

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

CMyData utiliza el mecanismo AssertValid para probar la validez de los objetos almacenados en su miembro de datos.El sustituto AssertValid de CMyData invoca la macro ASSERT_VALID para su propia variable miembro m_pDataList.

Pruebas de validez no detiene en este nivel porque la clase CObList también invalida AssertValid.Esta sustitución ejecuta pruebas de validez adicionales sobre el estado interno de la lista.Así, una prueba de validez sobre un objeto CMyData conduce a pruebas de validez adicionales sobre los estados internos del objeto de lista CObList almacenado.

Con algo más de trabajo, se podrían también agregar pruebas de validez para los objetos CPerson almacenados en la lista.Se podría derivar una clase CPersonList de CObList y reemplazar AssertValid.En el método reemplazado, se llamaría a CObject::AssertValid y, a continuación, la lista se recorrería en iteración, llamando a AssertValid para cada objeto CPerson almacenado en la lista.La clase CPerson mostrada al principio de este tema ya reemplaza la función AssertValid.

Se trata de un mecanismo muy eficaz de las versiones de depuración.Cuando, posteriormente, se compilan versiones de lanzamiento, el mecanismo se desactiva automáticamente.

ww5t02fa.collapse_all(es-es,VS.110).gifLimitaciones de AssertValid

Si se desencadena una aserción, el objeto es definitivamente defectuoso y la ejecución se detendrá.Sin embargo, la falta de aserción sólo indica que no se encontró ningún problema, pero no garantiza que el objeto sea correcto.

En este tema

Mediante aserciones

ww5t02fa.collapse_all(es-es,VS.110).gifErrores lógicos de detección

Se puede definir una aserción sobre una condición que debe ser cierta según la lógica del programa.La aserción no tiene ningún efecto a menos que se produzca un error de lógica.

Por ejemplo, suponga que está simulando moléculas de gas en un contenedor y que la variable numMols representa el número total de moléculas.Este número no puede ser menor que cero, por tanto, se podría incluir una instrucción de aserción de MFC como ésta:

ASSERT(numMols >= 0);

O bien, podría incluir una aserción de CRT como ésta:

_ASSERT(numMols >= 0);

Estas instrucciones no hacen nada si el programa funciona correctamente.Si un error lógico hace numMolssea menor que cero, sin embargo, la aserción detiene la ejecución del programa y muestra Cuadro de diálogo Error de aserción.

En este tema

ww5t02fa.collapse_all(es-es,VS.110).gifComprobar los resultados

Las aserciones tienen valores para operaciones cuyos resultados no son obvios con una inspección visual.

Por ejemplo, considere el siguiente código, que actualiza la variable iMols según el contenido de la lista vinculada a la que apunta 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

El número de moléculas contadas por iMols debe ser siempre menor o igual que el número total de moléculas, numMols.La inspección visual del bucle no muestra que éste sea necesariamente el caso, por lo que se utiliza una instrucción de aserción después del bucle para probar esa condición.

En este tema

ww5t02fa.collapse_all(es-es,VS.110).gifBuscar errores no controlados

Se pueden utilizar aserciones para probar condiciones de error en un punto del código en el que cualquier error se debería haber controlado.En el siguiente ejemplo, una rutina gráfica devuelve cero si no hay error, o un código de error, en caso contrario.

myErr = myGraphRoutine(a, b);

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

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

Si el código de tratamiento del error funciona correctamente, el error debería recibir el tratamiento adecuado y myErr se debería restablecer a cero antes de alcanzar la aserción.Si myErr tiene otro valor, se produce un error en la aserción, el programa se detiene y aparece Cuadro de diálogo Error de aserción.

No obstante, las instrucciones de aserción no son un sustituto del código de control de errores.El siguiente ejemplo muestra una instrucción de aserción que puede causar problemas en el código final de la versión de lanzamiento:

myErr = myGraphRoutine(a, b);

/* No Code to handle errors */

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

Este código se basa en la instrucción de aserción para controlar la condición de error.Como resultado, ningún código de error devuelto por myGraphRoutine dispondrá de tratamiento en el código de la versión de lanzamiento.

En este tema

Vea también

Referencia

Aserciones en el código administrado

Conceptos

Seguridad del depurador

Otros recursos

Depuración de código nativo