2012-03-06 21 views
5

por ejemplo, esta función f definida así:¿Por qué puede devolver una función por referencia para una variable local y no para una variable temporal? C++

int f(int x){return x;} 

como sepa que no puede asignar una referencia a la presente int temporal:

int& rf=f(2);// this will give an error 

pero si redefiní mi función f como esto :

int& f(int x){return x;} 
f(2);// so now f(2) is a reference of x, which has been destroyed 

así que mi pregunta es: ¿cómo puede el compilador no le permite crear una referencia a una temperatura orario que se destruirá después de la declaración (en el primer caso). y, por otro lado, le permite crear una referencia f (2) a x, mientras que el compilador sabe que este será destruido después de return.

+1

Esto es UB (bueno, accediendo a la referencia, de todos modos) y cualquier compilador en serio le avisará al respecto. –

Respuesta

7

Volviendo una referencia a un local es algo que puede ser difícil o imposible para el compilador de detectar. Por ejemplo:

int & f() 
{ 
    int x; 
    extern int & g(int & x); 

    // Does this return a reference to "x"? 
    // The compiler has no way to tell. 
    return g(x); 
} 

Incluso sin llamar a las funciones externas, que todavía puede ser difícil de analizar un flujo de programa complejo para decir si la referencia es devuelto a un local; en lugar de tratar de definir lo que se considera "lo suficientemente simple" para diagnosticar, el estándar no requiere un diagnóstico; solo establece que proporciona un comportamiento indefinido. Un buen compilador debería dar una advertencia, al menos en casos simples.

Enlazar una referencia temporal a no referencia es algo que el compilador puede detectar fácilmente, por lo que el estándar requiere un diagnóstico para eso.

1

Porque, como especifica la norma, devolver una referencia a una variable temporal de una función es un comportamiento indefinido.

¿Qué pasa en realidad es la definición de función:

int& f(int x) 
{ 
    return x; 
} 
0

que no es una buena idea para volver por referencia a menos que esté seguro de la referencia usted está volviendo todavía estará apuntando a algo válido.

de lo contrario, se espera un comportamiento indefinido.

ya que la variable es local, puede estar seguro de que teh referencia no es válida

+2

Dado que la variable es local, puede estar seguro de que no es válida. –

1

Puede vincular el valor r temporal a una referencia permanente para prolongar su vida útil.

const int& rf=f(2); 
0

El problema es que semánticamente no hay diferencia entre una variable en una pila, o una variable en el montón etc. - Así que el idioma no tiene más remedio que permitir esto, incluso si es un comportamiento indefinido. En el primer ejemplo, obtiene un error de compilación fácil, porque está intentando vincular una referencia en una variable temporal, que puede estar prohibida por el idioma.

+0

sí Lo entiendo pero ¿por qué funciona para el segundo ejemplo? y por qué mencionaste el montón, y no dije nada sobre el montón – AlexDan

+0

@AbdessamadBond. Aquí está la respuesta de por qué tu segundo ejemplo no funciona ... y mencioné el montón, porque devolver una referencia a una variable en el montón es ok (incluso si es probablemente un mal estilo). Semánticamente no hay diferencia entre una variable en el montón y una en la pila, mientras que hay una diferencia entre una variable y un valor temporal. – cooky451

1

Para rechazar el primer fragmento de código, el compilador aplica la regla simple de que no se puede vincular directamente una referencia temporal a una referencia no constante.

Para rechazar el segundo, el compilador tal vez podría aplicar una regla que la declaración return de una función que devuelve por referencia no puede ser el nombre de una variable automática (incluido un parámetro de función by-value). Eso me parece una regla bastante fácil también.

No sé por qué el estándar no especifica que hacerlo está mal formado. No puedo pensar en ningún uso válido para él, pero quizás en el momento del primer estándar habría creado una carga excesiva en alguna implementación u otra. O tal vez se pensó que era solo la mitad de una solución y no valía la pena molestarse (hay muchas otras formas de crear una referencia que cuelga, esto solo bloquea una de ellas).

La razón por la que el estándar no lo detiene en general para crear una referencia no const vinculada a un temporal es que hay ocasiones en las que está bien. Por ejemplo:

struct Foo { 
    static void set(Foo &f) { f.val = 0; } 
    int val; 
    int bar() { 
     set(*this); 
     return val; 
    } 
}; 

std::cout << Foo().bar() << "\n"; 

Aquí Foo() es una temporal, y la línea de set(*this) se une a una referencia no const (pero no directamente, se utiliza una expresión lvalue *this que se refiere a un temporal algunas veces, pero no otros) . Aquí no hay ningún problema, el temporal sobrevive a la referencia. Por lo tanto, sería innecesariamente restrictivo para el lenguaje el evitar de alguna manera que cualquier temporal se vincule a una referencia que no sea const.

Cuestiones relacionadas