2011-08-20 12 views
6

Si no accedo realmente al "objeto" desreferenciado, ¿la desreferenciación del puntero nulo aún no está definida?¿En qué punto desreferenciar el puntero nulo se convierte en un comportamiento indefinido?

int* p = 0; 
int& r = *p; // undefined? 
int* q = &*p; // undefined? 

Un ejemplo un poco más práctico: puedo eliminar la referencia al puntero nulo para distinguir entre las sobrecargas?

void foo(Bar&); 
void foo(Baz&); 

foo(*(Bar*)0); // undefined? 

bien, los ejemplos de referencia son el comportamiento definitivamente no definido de acuerdo con la norma:

una referencia nula no puede existir en un programa bien definido, ya que la única manera de crear tal la referencia sería vincularla al "objeto" obtenido desreferenciando un puntero nulo, , que causa un comportamiento indefinido.

Desafortunadamente, la parte destacada es ambigua. ¿Es la parte vinculante que causa un comportamiento indefinido, o es desreferenciando parte suficiente?

+0

[Esta pregunta cubre la información que desea.] (Http://stackoverflow.com/questions/2474018/when-does-invoking-a-member-function-on-a-null-instance-result-in- undefined-behav) – GManNickG

+0

Esto debe ser un engaño exacto. Sé que hemos discutido esto antes. –

Respuesta

2

Sí, es un comportamiento indefinido, porque la especificación dice que "lvalue designa un objeto o función" (en la cláusula 3.10) y dice para el operador * "el resultado [de desreferenciación] es un valor l referente al objeto o función a la que apunta la expresión "(en la cláusula 5.3.1).

Eso significa que no hay una descripción de lo que sucede cuando desreferencia un puntero nulo. Es simplemente un comportamiento indefinido.

+0

(Se ha discutido en otras preguntas en SO. Por lo tanto, creo que no estoy elaborando de nuevo). –

5
int& r = *p; // undefined? 

Creo que aquí tienes un comportamiento indefinido, incluso si no lo hace realidad uso r (o *p) - el objeto sin referencia. Porque después de este paso (es decir, desreferenciar el puntero nulo), el comportamiento del programa no está garantizado por el idioma, ya que el programa puede bloquearse inmediatamente, lo que es una de las posibilidades de UB. Usted parece pensar que solo leyendo el valor de r para ser usado en real propósito invoca UB. No lo creo.

Además, la especificación del lenguaje indica claramente "el efecto de desreferenciar el puntero nulo" invoca un comportamiento indefinido. Lo hace no decir "el efecto de en realidad usando un objeto desreferenciado desde un puntero nulo" invoca UB. El efecto de la eliminación de referencias del puntero nulo (o en otras palabras comportamiento indefinido) no significa que vaya a necesaria e inmediatamente tener problemas, o debe chocar inmediatamente después de la eliminación de referencias del puntero nulo. No. Simplemente significa que el comportamiento del programa no está definido en después de desreferenciando el puntero nulo. Es decir, el programa puede funcionar normalmente, como se esperaba, de principio a fin. O puede bloquearse inmediatamente o después de un tiempo, después de algunos minutos, horas o días. Todo puede suceder en cualquier momentodespués de desreferenciando el puntero nulo.

+0

No puedo encontrar "el efecto de desreferenciar el puntero nulo" en el estándar. ¿Dónde exactamente lo encontraste? – fredoverflow

+1

@FredOverflow: §1.9/4 (C++ 03) dice 'Algunas otras operaciones se describen en esta norma internacional como indefinidas (por ejemplo, el efecto de desreferenciar el puntero nulo). [Nota: esta Norma Internacional no impone requisitos sobre el comportamiento de los programas que contienen un comportamiento indefinido. ] ' – Nawaz

+0

El FDIS reemplazó el ejemplo de puntero nulo con' por ejemplo, el efecto de intentar modificar un objeto const', que podría indicar que las reglas sobre desreferenciar el puntero nulo han cambiado. – fredoverflow

4

Creo que el segundo opus de What every C programmer should know about Undefined Behavior podría ayudar a ilustrar este problema.

Tomando el ejemplo del blog:

void contains_null_check(int *P) { 
    int dead = *P; 
    if (P == 0) 
    return; 
    *P = 4; 
} 

podría ser optimizado para (RNCE: redundante NULL Registro Elimintation):

void contains_null_check_after_RNCE(int *P) { 
    int dead = *P; 
    if (false) // P was dereferenced by this point, so it can't be null 
    return; 
    *P = 4; 
} 

Cuál es a su vez optimizado en (DCE: Código Muerto eliminación) :

void contains_null_check_after_RNCE_and_DCE(int *P) { 
    //int dead = *P; -- dead store 
    //if (false)  -- unreachable branch 
    // return; 
    *P = 4; 
} 

Como se puede ver, a pesar de que es deadnunca utilizado, la asignación simple int dead = *P ha causado un comportamiento indefinido para arrastrarse en el programa.

Para distinguir entre sobrecargas, sugiero usar un puntero (que puede ser nulo) en lugar de crear artificialmente una referencia nula y exponerse a un Comportamiento no definido.

Cuestiones relacionadas