2010-09-09 24 views
7

Me preguntaba, ¿por qué la siguiente forma de código (ya comentada) hará que
C2102: '&' requires l-valuePor qué esto está causando C2102: '&' requiere valor L

¿Hay una mejor manera de evitar el uso de tmp variables ?

class a { 
private: 
    int *dummy; 
public: 
    int* get_dummy() const { 
     return dummy; 
    } 
}; 

int main() 
{ 
    a aa; 

    // error C2102: '&' requires l-value 
    //int** me = &(aa.get_dummy()); 

    // OK! 
    int *tmp = aa.get_dummy(); 
    int** me = &(tmp); 
} 
+0

devuelve una referencia al puntero. –

+0

Posible duplicado del error ["l-value required"] (http://stackoverflow.com/questions/1353384/l-value-required-error) – sigy

Respuesta

4

Porque a::get_dummy() devuelve objeto temporal sin nombre (puntero int).
El objeto devuelto por la función se encuentra en la parte superior del marco de la pila y no tiene sentido obtener su dirección, ya que puede ser no válido después de que termine la expresión.

+0

Mismo problema que la respuesta de Luca. 'tmp' es un objeto de pila! –

+0

'dummy' no es un objeto temporal o un objeto local. – Naveen

+0

@Naveen: Sí, eso es cierto. Pero la respuesta no dice "temporal sin nombre" (que vive hasta el final de su expresión), sino que dice "objeto de pila", que generalmente significa un objeto en almacenamiento "automático" que vive hasta el final de su alcance. –

4

¿A qué dirección habría me contener lo contrario? Aquí le dio la dirección de tmp, pero si la reemplaza por int** me = &aa.get_dummy();, ¿dónde indicaría?

No hay una respuesta significativa a esa pregunta, por lo que el estándar requiere que el argumento de & sea un valor l.

+0

'¿dónde indicaría esto?' - ¿No es el punto del dirección de la instancia ficticia? –

+0

@Yan: No. La función devuelve la dirección (o valor) almacenada por 'dummy', no' dummy'. –

+1

@Yan: puede devolver el dummy por referencia, p. int * y get_dummy. – Puppy

7

Se podría en lugar de definir:

int **get_dummy() ... return &dummy; 

Se puede pensar en un valor de r como una expresión, esencialmente, mientras que un valor L es un objeto real. Las expresiones no tienen direcciones, y aunque lo hicieran, es difícil imaginar qué tan buena sería la dirección. Es fácil entender cómo la dirección de un objeto puede ser útil.

Es un poco difícil entender un problema como este de manera abstracta. La mejor manera de comprender los punteros y los lenguajes compilados es aprender el lenguaje ensamblador.

+1

+1 por sugerir una solución razonable al problema. –

+0

No tengo acceso al código fuente get_dummy. –

+0

Hmm, es posible que pueda usar '& aa', pero de lo contrario, ¿por qué quiere el puntero indirecto? ¿No hay API para cambiar el puntero? ¿Incluso quieres cambiarlo? Es peligroso tomar la dirección de una variable local ... – DigitalRoss

0

El operador & se debe aplicar a un lvalor. Cuando la llamada aa.get_dummy() no está asignada a una variable, su valor de retorno solo se coloca en la pila, por lo que sería absurdo (y erróneo) obtener la dirección de un elemento de la pila.

+2

Err .. 'tmp' es un elemento de la pila. –

+0

Quise decir elemento de pila sin nombre –

0

El compilador es correcto, de acuerdo con ISO C++ § 5.3.1.3:

El resultado de la & operador unario es un puntero a su operando. El operando debe ser un lvalue o un id calificado.

En otras palabras, se puede tomar una dirección de cualquier cosa que tiene un nombre .

valores devueltos por las funciones por valor no tienen nombre y son a menudo devuelto a través de un registro. Por lo tanto, no hay una "dirección" para mencionar que el valor no reside en la memoria.

Se podría argumentar que el compilador podría ser más inteligente, detectar esto y almacenar el valor en la pila durante la expresión en la que se usa la dirección.Pero eso es propenso a errores (puede "filtrar" un puntero a fuera de la expresión), y claramente sería una extensión del estándar (es decir, no se garantiza que sea compatible). Entonces, MSVC simplemente lo prohíbe.

Enteramente, el compilador is that smart cuando se trata de una referencia a un valor r. Pero no hay tal funcionalidad para un puntero en un valor r.

Para responder a su pregunta: intente minimizar la toma de direcciones de cosas; tomar una dirección de una variable evita que el optimizador la incluya en un registro. Pero si es necesario, devolver una referencia en su lugar:

class a { 
private: 
    int dummy; 
public: 
    int get_dummy() const { 
     return dummy; 
    } 
    int& get_dummy() { 
     return dummy; 
    } 
}; 

int main() 
{ 
    a aa; 

    int* me = &(aa.get_dummy()); 
} 

Nota que tener un const get_dummy() no es estrictamente necesario, pero ayudará a que el optimizador en contextos rvalue.

Cuestiones relacionadas