Pregunta

He heredado una gran c ++ código base y tengo una tarea para evitar cualquier excepción de puntero nulo que pueden suceder en la base de código. Es que hay disponibles herramientas de análisis estático, estoy pensando pelusa, que se han utilizado con éxito.

¿Qué otras cosas que tener en cuenta?

¿Fue útil?

Solución

Puede empezar por eliminar las fuentes de NULL:

Cambiar

if (error) {
    return NULL;
}

En

if (error) {
    return DefaultObject; // Ex: an empty vector
}

Si va a devolver objetos predeterminados no se aplica y su base de código ya utiliza excepciones, hacer

if (error) {
    throw BadThingHappenedException;
}

A continuación, añadir la manipulación en los lugares adecuados.

Si está trabajando con código anterior, usted podría hacer algunas funciones de contenedor / clases:

ResultType *new_function() {
    ResultType *result = legacy_function();
    if (result) {
        return result;
    } else {
        throw BadThingHappenedException;
    }
}

Las nuevas funcionalidades deben comenzar a utilizar nuevas funciones y tienen un manejo adecuado excepción.

Sé que algunos programadores simplemente no conseguir excepciones, incluyendo a las personas inteligentes como Joel . Pero, lo que termina pasando devolviendo NULL NULL es que este se pasan como locos ya que todo el mundo se acaba de pensar que no es su negocio para manejar la situación y volver en silencio. Algunas funciones pueden devolver el código de error, lo cual está bien, pero la persona que llama a menudo termina volviendo sin embargo, otro nulo en respuesta a errores. A continuación, se ve una gran cantidad de NULL de comprobación en cada funciones individuales, no importa lo trivial es la función. Y, todo lo que necesita es sólo un lugar que no comprobar NULL se bloquee el programa. Excepciones te obligan a pensar cuidadosamente acerca del error y decide exactamente dónde y cómo debe manejarse.

Parece que estás en busca de soluciones fáciles, como herramientas de análisis estático (que siempre debe utilizar). Cambio de punteros a referencias es también una gran solución también. Sin embargo, C ++ tiene la belleza de RAII, lo que elimina la necesidad de tener "try {} finally {}" en todas partes, así que creo que merezca la pena su consideración seria.

Otros consejos

Si está manteniendo principalmente la base de código, una de las cosas más bajas y del grado de esfuerzo más alto retorno se puede hacer es empezar refactorización sus punteros desnudos a referencia contó punteros .

También me miro algo así como Purificar que será su código de instrumento para detectar corrupción de memoria.

En primer lugar, como un elemento técnico, C ++ no tiene excepciones de puntero nulo. Eliminación de referencias a un puntero NULL ha indefinido comportamiento, y en la mayoría de los sistemas hace que el programa de interrumpir bruscamente ( "accidente").

En cuanto a las herramientas, yo también recomiendo la pregunta:

son de código estático C ++ analyis herramientas vale la pena?

En cuanto a desreferencias puntero nulo, en particular, considerar que una referencia a un puntero NULL tiene tres elementos principales:

  1. La introducción de un puntero NULL.
  2. El flujo de ese puntero en el programa en otro lugar.
  3. La eliminar la referencia de ese puntero.

La parte difícil para una herramienta de análisis estático es de paso curso 2, y las herramientas se diferencian por lo complicado que un camino que pueden precisión (es decir, sin demasiados falsos positivos) pista. Podría ser útil para ver algunos ejemplos específicos de los insectos que se desea capturar con el fin de asesorar mejor sobre qué tipo de herramienta será más eficaz.

exención de responsabilidad: yo trabajo para Coverity

.

Si no desea cambiar ningún código, usted tiene que utilizar algunas herramientas (ver otras respuestas). Sin embargo, para una parte especial del problema (donde se coloca un puntero en una función de usarlo) hay un pequeño Makro-Definición podría utilizar para encontrar algunos pequeños bichos: (Sin sobrecarga de tiempo de la liberación de modo y añade una condición visible para el código)

    #ifdef  NDEBUG

    #define NotNull(X) X

    #else // in Debug-Mode

    template<typename T> class NotNull;

    template<typename T> // template specialization only for pointer-types
    class NotNull<T*> {
    public:
        NotNull(T* object)
        : _object(object) {
            assert(object);
        }

        operator T*() const {
            return _object;
        }

        T* operator->() const {
            return _object;
        }
    private:
        T *_object;
    };

    #define NotNull(X) NotNull<X>

    #endif // in Debug-Mode

Se acaba de cambiar todas las funciones de esta:

void increase(int* counter)  
{ .. } 

a este

void increase(NotNull(int*) counter)
{ .. }  

p.s: AQUÍ y puede ser ajustado aún más

Una pregunta lado, es el fin de evitar estos porque no quieren que el cliente vea un accidente? En muchos casos punteros nulos son condiciones inesperadas que deben ser manejadas de inmediato, pero con demasiada frecuencia se pasan a través del sistema como una patata caliente.

Una vez trabajé en una base de código, donde el hábito era la entrada en una función, a primera verificación de los punteros nulos y si es así, el retorno. El problema con esto es mientras que la herramienta no se estrelló, en última instancia, genera malos datos en silencio. Y tratando de depurar estos problemas era difícil porque no podrían haber sido ilegalmente punteros nulos que se pasa alrededor de un largo tiempo a través de muchas funciones antes de los resultados se hizo intolerable o al final tuvo que manifestarse.

Lo ideal es que las afirmaciones correctas por lo menos durante su período de desarrollo, por lo que considera una macro para ocultar o redefinir la aserción de la producción se basa

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top