Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





GCC 4 y los rvalues como parámetros a función

Iniciado por Zaelsius, 16 de Febrero de 2008, 04:48:53 PM

« anterior - próximo »

Zaelsius

Hola, resulta que estoy portando el código de una aplicación C++ de VC 6 a GCC 4, y hay muchos lugares donde se usa un rvalue como parámetro a una función que espera una referencia del mismo tipo. Ejemplo:

void foo( int& a )
{

}


int main()
{
int a = 0;

foo( a ); // OK
foo( int(69) ); // Error
foo( (int&)int(69) ); // Error con GCC 4. GCC 3 se traga el cast.

return 0;
}


Obviamente, en el código real no se usan simples enteros, sino estructuras de datos más pesadas. En una ocasión anterior, portando una aplicación similar de VC6 a GCC 3.3, un cast me bastaba para forzar al compilador a tragarse el parámetro, pero el nuevo GCC 4 ya no admite trampa ninguna. Los casts modernos (static_cast, reinterpret_cast) también devuelven un error (lógicamente).

Aunque entiendo perfectamente porqué el código es ilegal desde el punto de vista del estándar de C++, y las diferencias entre tipos lvalue y rvalue, me gustaría saber si conocéis de algun 'workaround' para esta situación y así minimizar el código a modificar.

davur

El código tal y como está tiene un comportamiento indefinido. Lo único más cercano a no serlo sin modificar la llamada está en cambiar el tipo del argumento de foo a const int& (porque el estándar de C++ especifica de manera deliberada que asociar un objeto temporal a una referencia a constante en la pila alarga el tiempo de vida del temporal al tiempo de vida de esa referencia), pero eso  sólo te será útil si foo no modifica su argumento, lo cual posiblemente no sea el caso porque, de serlo, éste ya sería (tendría que ser) referencia a constante en primer lugar.

No hay manera definida por el estándar del lenguaje de pasar un objeto temporal a una función que toma una referencia a no constante como parámetro. Sólo los lvalues se pueden asociar a referencias a no constantes.

jalbam

Hola, buenas.

Perdona la ignorancia, pero ¿qué significa utilizar el signo &?

Lo he buscado por Internet pero no encuentro nada que responda a mi pregunta.

Hasta lo que yo he estudiado, sólo he utilizado el signo * en los prototipos de las funciones y en sus declaraciones para indicar que se va a recibir la dirección de memoria de una variable (un puntero). Y el signo & lo he utlizado para pasar la direccion de una variable que no es un puntero ni un vector/matriz (si lo fuera ya no haría falta ningún signo) a una función de este tipo, como es el caso de la conocida función scanf.

¿Es algo de funciones que reciben otras funciones pasadas por parámetro, callback?

Gracias. Siento la ignorancia y el off-topic :)

Saludos.
-----
Juan Alba Maldonado

Pogacha

Suponiendo que conozcas el tipo de parametro de foo y este sea definido se me ocurre que en algunos casos el workaround mas sencillo deberia ser usar un macro del tipo

#define foo(X) { int _temp_ =(X); foo( _temp_ );  }

Pero esto no es aplicable a todos los casos seguramente.

Lo mejor es que hables con la persona que hizo esta macana y le digas que escriba bien el codigo de forma que ande en todos los compiladores :P (seguramente a el tambien le va a interesar)

Saludos

Zaelsius

@Jalbam: El uso del símbolo & en el código de arriba tiene que ver con el paso de parámetros a funciones por referencia, una característica de C++ que no está en C.

jalbam

Muchas gracias por la respuesta :)

La verdad es que no es la primera vez que lo veo pero no sabía qué era.

Por lo que he leido parece ser igual que cuando pasas por referencia un puntero pero esta vez es de forma "constante", sin poder modificar la variable a la que apunta.
-----
Juan Alba Maldonado

Pogacha

Pues no,
para que sea constante tienes que poner el modificador "const"foo(const int& variable)
{
variable = 1; // error
}

foo(int& variable)
{
variable = 1; // valido!
}
La diferencia de la referencia es que siempre apunta a un elemento valido (o almenos asi deberia)

En cambio un puntero puede apuntar a NULL

Otra diferencia es que la referencia es inoperable, no puedes desplazarte sobre ella como en un puntero (excepto que hagas unos casting a punteros y luego a referencia)

Y otra tambien es que la referencia es un elemento nuevo de C++ y aporta mas datos al compilador.

Saludos

Zaelsius

Por cierto, gracias a Davur y Pogacha. En efecto, añadir el 'const' al parámetro por referencia soluciona la papeleta. ¡Gracias!

Pogacha

En realidad el crédito es de Davur, yo también recién me desayuno que pasar un objeto temporal por referencia como parámetro no constante de una función es un error y no tan solo una práctica insegura.
VC6 te permite hacer esas aberraciones :X

LC0

Para la gente que no entienda el uso de & (en este caso jalbam), es exactamente lo mismo que usar un puntero constante. Solo que así se simplifica la sintaxis y se puede referenciar de una forma muy fácil de escribir parámetros por referencias (valga la redundancia :D).

Yo, por mi parte, acostumbrado al GCC me he quedado boquiabierto al ver que Visual C++ se traga el código de Zaelsius. ¿Has probado a modificar el parámetro a en foo (compilando desde el Visual), a ver que pasa? ¿No sería código potencialmente inseguro?

tamat

LC0, no tiene por qué, a mi entender estas modificando una variable local de la función externa, otra cosa es que esa variable no tiene nombre, otra cosa es si no se hubiera casteado a int, porque entonces sí que estarias modificando una constante.
Por un stratos menos tenso

ethernet

Es que en mi opinión carece de sentido tener pasar un valor constante para ser modificado, es igualq que hacer:

int a;
...
5 = a;

tamat

si, pero al hacer int(5) creo que ya no es una constante. Yo hablo a nivel de compilador, no de concepto.
Por un stratos menos tenso

fjfnaranjo

Que hermoso sería el mundo si todos compilasemos con "-ansi -pedantic-errors"  :P
fjfnaranjo.com - Creating entertainment - Creando entretenimiento
fjfnaranjo [4t] gm4il [d0t] c0m (mail y msn)






Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
Muchísimas gracias.