2010-09-15 7 views
5

Me acaba de picar un comportamiento indefinido desagradable debido a la devolución de una referencia a una variable local.Detección del compilador de la referencia de devolución a la variable local

Sabemos que es malo, y en general el compilador imprime un buen warning para decirnos ... bueno, gcc (3.4.2) no parece llevar los controles demasiado lejos.

std::string get_env_value(std::string const& key); 

std::string const& get_phase() 
{ 
    std::string const& phase = get_env_value("PHASE"); // [1] 
    std::cout << "get_phase - " << phase << '\n'; 
    return phase;          // [2] 
} 

Se compila sin problemas y, sin embargo, caemos en el asqueroso reino del comportamiento indefinido.

La línea [1] está bien porque el estándar especifica que la duración de una variable vinculada a una referencia constante debe extenderse para coincidir con el tiempo de vida de la referencia constante.

Línea [2] parece bien también ...

  • No especificaciones del C++ cubren este caso?
  • ¿Alguien sabe si esto generalmente se diagnostica? (I puede pasar por alto una bandera o algo ...)

Me parece que el análisis estático debe ser capaz de decir que tiene usar una "extensión de vida" para [1], [2] no es seguro, pero podría conseguir feo rápidamente, supongo ...

+0

¡Maldición, es un caso desagradable! –

+1

Eventualmente es posible que 'get_env_value()' devuelva una referencia a una variable que no está fuera del alcance, por ejemplo, global, en cuyo caso todo debería estar bien. – UncleBens

+0

@UncleBens: ese es un buen punto – Chubsdad

Respuesta

5

La norma no cubre [2]. Permite que un valor r se vincule a una referencia constante, pero eso no le permite devolver una referencia constante y tener la vida útil del valor r que está obligado a extenderse también.

Y verdadero, análisis estático podría captar esto, pero como siempre es una desventaja. La compilación de C++ es lo suficientemente lenta como es, por lo que los escritores de compiladores tienen que sopesar los beneficios de un análisis estático adicional que les permita producir mejores diagnósticos, en comparación con el aumento del tiempo de compilación.

+0

¿Se puede configurar la pelusa para atrapar esto? –

+0

Estoy de acuerdo en que la compilación es lo suficientemente lenta, el compilador advierte sobre retornos faltantes y devuelve referencia a variables locales, de alguna manera esperé que 'phase' levantara la advertencia:/ –

2
  1. No, no creo que el estándar mencione/cubra este caso específico.

  2. VS 2010 da advertencias de compilación (/ Za,/W4).

Por lo tanto, definitivamente parece ser una condición diagnosticable.

Así, pellizqué ligeramente la función de la siguiente manera, sólo para crear múltiples vías de retorno:

std::string const& get_phase() 
{ 
    std::string const& phase = get_env_value("PHASE"); // [1] 
    std::cout << "get_phase - " << phase << '\n'; 

    if(1){ 
     while(1){ 
      return phase; 
     } 
    } 
    return phase;          // [2] 
} 

Ahora, VS no informa a la advertencia anterior.

Como ejemplo, a primera vista, parece que debería ser fácil para el compilador detectar y detectar que no todas las rutas devuelven un valor. Pero los compiladores (por ejemplo, VS) no lo hacen.

int get_phase() 
{ 
    char ch; 
    if(ch){ 
     return 0; 
    } 
    // nothing returned from here. 
} 

Por lo tanto, supongo que el código de OP tiene probablemente las mismas complejidades para diagnosticar la condición como el ejemplo que se muestra justo por encima, aunque no estoy seguro. Lo único bueno es que el estándar es claro en este caso.

$ 6.6.3/2 - "que fluye fuera de la final de una función es equivalente a un retorno sin valor, lo que se traduce en un comportamiento indefinido en una función de retorno de valor ."

Volviendo al código en OP, supongo que el estándar no exige que esta condición sea una condición diagnosticable, y por lo tanto los compiladores son libres de hacer lo que quieran. Básicamente se entiende que la referencia devuelta apunta a un objeto que ya está destruido. Por lo tanto, el acceso a dicho objeto dará lugar a un comportamiento indefinido

+0

@Chusbad: la mayoría de los compiladores advierten sobre funciones sin retorno (a veces abusivamente, pero solo en casos de esquina). Realmente no esperaba un error ... pero una advertencia sería muy buena :) –

Cuestiones relacionadas