2010-04-08 14 views
14

Esto fue un error que encontré en una aplicación de servidor usando Valgrind.¿Inicializar un miembro de referencia consigo mismo es legal?

struct Foo 
{ 
    Foo(const std::string& a) 
     : a_(a_) 
    { 
    } 
    const std::string& a_; 
}; 

con gcc -Wall usted no recibe una advertencia. ¿Por qué es este código legal?

+0

Desafortunadamente gcc nunca parece advertir acerca de la auto-inicialización en las listas de inicializador (incluso con -Wall -Wextra) - es realmente molesto si le gusta dar a los parámetros del ctor los mismos nombres que los miembros, porque un error tipográfico en el parámetro hará que la inicialización falle silenciosamente. –

+0

-Wextra advierte sobre el parámetro no utilizado 'a', que es una buena pista, pero no detectó el problema real. –

+0

Ni siquiera con -Winit-self :( – UncleBens

Respuesta

2

Lo que tienes viola 8.3.2/4 A ... reference shall be initialized to refer to a valid object or function. Por lo tanto, es ciertamente ilegal.

Tenga en cuenta que no todos los programas erróneos deben ser detectados por el compilador, aunque honestamente habría pensado que este era uno de ellos.

Por lo que vale la pena, g ++ versión 4.4.1 con las advertencias del compilador máximas encendidas felizmente acepta este programa sin una advertencia, ya sea:

int main(void) 
{ 
    int *p = 0; 
    *p = 5; 
} 
+1

Los compiladores generalmente no pueden detectar todas las violaciones, por ejemplo, en 'void f (int * p) {int & r = * p;/* ... * /}' la inicialización de referencia puede ser legal en algunas llamadas a 'f', pero no en otras donde' p' se pasa como nulo –

+0

Es comprensible que el compilador no pueda detectar algo que solo es válido o inválido en el tiempo de ejecución, pero en este caso se puede demostrar estáticamente que la referencia nunca puede ser inicializada por un objeto real. – janks

+0

Sí, mi punto era solo eso porque no puedes _siempre_ detectar inicializaciones de referencia incorrectas Los implementadores de compiladores pueden no implementar _todas las comprobaciones de inicialización de referencia incorrectas incluso cuando hay casos en que es obviamente malo para los ojos humanos. Es potencialmente mucho trabajo extra (más compilaciones más lentas) con una ganancia potencialmente pequeña. –

0

La autoasignación está permitida en C/C++ (y consideraría esto un defecto en el lenguaje).

Desde el punto de vista del modelo de memoria, Foo :: a_ es simplemente algún lugar de la memoria y en la lista de inicialización que se le asigna el valor de otra posición de memoria, que en este caso especial es por desgracia el mismo lugar.

Hay una falla similar en C, donde se puede hacer esto:

void foo() 
    { 
    int i = i; 
    } 
+0

En realidad, el estándar dice explícitamente que las referencias no tienen que ocupar una ubicación de memoria: '8.3.2/3 No se especifica si una referencia requiere almacenamiento (basic.stc)' – janks

Cuestiones relacionadas