Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: botella en 7 Julio 2010, 16:01 pm



Título: warning al pasar por referencia una variable local.
Publicado por: botella en 7 Julio 2010, 16:01 pm
Buenas, tengo un problema de concepto que no logro resolver de ninguna manera.

Doy un ejemplo rápido y abajo dejo el codigo completo de la clase racional que no es más que una clase para manejar números racionales.


En la sobrecarga de *,+, y - me encuentro que yo quiero devolver un valor que dentro de la función declaré como aux:

Racional& operator * ( Racional& r)
         {
                Racional aux;
                int deno,nume;
                deno= this->den * r.den;
                nume= this->num * r.num;
                aux.set_racional (nume,deno);              
                return aux;
        }

El programa funciona pero el compilador tira un warning:
 [Warning] reference to local variable `aux' returned

Y es lógico por que estoy pasando la dirección de memoria de un valor que desaparece con la función.
Pero funciona.
El tema es que si yo saco el &, para que la función en lugar de devolver una referencia devuelva la cosa en si misma:

Racional operator * ( Racional& r)
         {
                Racional aux;
                int deno,nume;
                deno= this->den * r.den;
                nume= this->num * r.num;
                aux.set_racional (nume,deno);              
                return aux;
        }


Esto también funciona, no tira el warning, pero tira el siguiente error al querer compilar:

 no match for 'operator=' in 'r3 = racional::operator*(Racional&)(((Racional&)(&r2)))'

Este error lo tira en la siguiente línea:
  r3 = r1 * r2;

Dejo el código completo funcionando, pero tirando los warnings.
Estoy laburando en dev++.
Alguien me dice si es que tengo que sobrecargar el operador = de alguna forma, o que tengo que hacer. Ya estuve buscando bastante en google y llegué a la conclusión de que el código está mal al pasar la referencia de un objeto que es una variable local, y quiero ver como solucionarlo.

saludos.

Código:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream.h>
#include <math.h>

class Racional
{
    private:
        int num;
        int den;
    public:
        Racional (void):num(1),den(1){}
        Racional (int a, int b) {this->set_racional(a,b);}
        Racional (Racional& r){this->set_racional(r.num,r.den);}
        ~Racional () {};
        
        Racional& operator = ( Racional& r)
        {
            this->set_racional(r.num,r.den);
            return *this;
        }
        
        friend ostream& operator << (ostream& sal, Racional& r)
        {
            sal<<r.num<<"/"<<r.den<<" ";
            return sal;
        }
        
        float get_real()
        {
            return (float)num/(float)den;
        }
        
        void set_racional (int n, int d)
        {int i,;
            for ( i=12; i>0; i--)
            if (n%i==0 && d%i==0) {n=n/i;d=d/i;}
            if (d<0 && n<0) { d=d*(-1);n=n*(-1);};
            this->num=n;
            this->den=d;
        }
            
        /*
        Racional& operator + ( Racional& r)
        {
            int deno,nume;
            Racional aux;
            deno=this->den*r.den;
            nume= (   (deno/this->den) * this->num +  (deno/r.den)* r.num );
            aux.set_racional (nume,deno);
            return aux;
        }*/
        
        friend Racional& operator + (Racional& r, Racional& t)
        {
            int deno,nume;
            Racional aux;
            deno=t.den*r.den;
            nume= (   (deno/t.den) * t.num +  (deno/r.den)* r.num );
            aux.set_racional (nume,deno);
            return aux;
        }
            
            
            
        
        Racional& operator++ ()
        {
            int deno,nume;
            deno=this->den;
            nume=this->num+deno;
            this->set_racional (nume,deno);
            return *this;
        }
              
        int operator!= ( Racional& r)
        {
            return ( this->den!=r.den || this->num!=r.num);
        }
        
        Racional& operator - ( Racional& r)
        {
            int deno,nume;
            Racional aux;
            deno=this->den*r.den;
            nume= (   (deno/this->den) * this->num -  (deno/r.den)* r.num );
            aux.set_racional (nume,deno);
            return aux;
         }
         Racional& operator * ( Racional& r)
         {
                Racional aux;
                int deno,nume;
                deno= this->den * r.den;
                nume= this->num * r.num;
                aux.set_racional (nume,deno);              
                return aux;
        }
        
        Racional& operator + (int a)
        {
            Racional aux;
            int deno,nume;
            deno=this->den;
            nume=this->num + (a * deno);
            aux.set_racional (nume,deno);
            return aux;  
        }
friend       Racional& operator + (int a,Racional& r)
        {
            Racional aux;
            int deno,nume;
            deno=r.den;
            nume=r.num + (a * deno);
            aux.set_racional (nume,deno);
            return aux;  
        }
};

int main()
{
   Racional r1(1,1), r2(3,11), r3, r4 ,r5, r6;// r7(r1 + r2);
   r3 = r1 * r2;
   r4 = r3 + 5;
   r5 = 8 + r1;
   r1= r2 - r3;
   r6 = (r3 + r5);
   r4 = r3 + r5;
  
   cout << r1 << r2 << r3 << r4 << r5 <<endl;
   if (r5 != r6)
      cout << "Son distintos" << endl;
   getchar();
   return 0;
}


Título: Re: warning al pasar por referencia una variable local.
Publicado por: EvilGoblin en 7 Julio 2010, 18:58 pm
usa los [ code][ /code]

tu codigo es verdaderamente complicado de entender xD
Pero en definitiva el "error" es que una vez que invocas a la funcion Racional, todo lo que invoques dentro de ella desaparece cuando la terminas

al pasarle valores de return, estas pasando aux (invocada dentro de Racional), asi que en programacion hay 2 alternativas... 1 dejar abierta la funcion (memoria reservada) para tener acceso , o liberar la memoria y pasar el puntero de esa informacion..

Opta por la 2da, osea te pasa el puntero de donde esta la informacion y libera la memoria cosa que te da el warning. si el programa se ejecutase por mucho tiempo ..

O va empezar a consumir cada vez mas memoria
o va a perder informacion.



PD: no pusiste si devueles un INT o CHAR a las funciones


Título: Re: warning al pasar por referencia una variable local.
Publicado por: do-while en 7 Julio 2010, 20:09 pm
Recuerda que el puntero this no esta de adorno.

si declaras ClaseQueSea& operator# (ClaseQueSea &UnObjeto); y en algun punto llamas al operdor # de la clase ClaseQueSea ( a#b), estas generando una llamada a.operator#(b). Desreferencia el puntero this, para poder devolver una referencia al objeto a una vez realizada la llamada al operador, de esta forma podras concatenar sucesibas llamadas a funciones con un mismo objeto.

Por ejemplo, tienes una clase hora, com mimebros setHora, setMinuto y setSegundos. Si cada una de estas funciones retorna una referencia al objeto que las ha llamado podrass realizar llamadas del tipo:

Hora reloj;

reloj.setHora(3).setMinuto(14).setSetgundo(16);

¡Saludos!


Título: Re: warning al pasar por referencia una variable local.
Publicado por: botella en 7 Julio 2010, 20:51 pm
Gracias por las respuestas, pero no tal vez expresé mal la pregunta:

Simple:

Así el código compila y funciona y tira un warning.

Yo se que está mal, se por qué esta mal y lo quiero hacer bién.

Yo no quiero modificar el this, yo quiero dar un resultado independiente.
Es decir que no voy a modificar al objeto llamador.

Racional& operator + ( Racional& r)
Racional aux;

return aux; (ese aux es un objeto no una referencia) por eso me putea el compilador.

Entonces la forma correcta es:

Racional operator + (Racional& r)
//codigo..codigo
return aux;

De esta forma el compildor no tira los warnings, pero me putea cuando desde el main hago r5= r6 + r7.

Se entiende?




Título: Re: warning al pasar por referencia una variable local.
Publicado por: do-while en 7 Julio 2010, 21:15 pm
¡Buenas!

Cuando en tiempos utilizaba C++, (lo usaba con devcpp), el echo de crear un variable temporal y querer utilizar una referencia a esta variable recien creada en una llamada a funcion no me daba mas que problemas. Y es lo que estas haciendo. Olvida lo que te he dicho sobre this, ya que en este caso el valor no queda almacenado en la variable llamadora al operador. Pueba a recibir como parametro en el operador de igualdad una variable de tipo Racional y no una referencia, y cuentanos que pasa.

¡Saludos!

Como trabajo en la uni hice una clase Complex, bastante completita. Si la encuentro (no se ni donde la tendre, porque de esto ya hace tres o cuatro años) te la paso, ya que tambien me encontre con todos esos "problemas".


Título: Re: warning al pasar por referencia una variable local.
Publicado por: botella en 7 Julio 2010, 22:09 pm
Ok, gracias.

Ya probé modificando el operator =, pero no dió resultado.

ya veremos.

ahora me voy a rendir el parcial

saludos.


Título: Re: warning al pasar por referencia una variable local.
Publicado por: carlitos_jajajajaja en 8 Julio 2010, 07:41 am
Te explico lo que entiendo


Veras, esta es la historia de tu variable local cuando devuelves su referencia...

1)Cuando llamas a la funcion, esta reserva espacio para la memoria de la funcion (crea un stack segun recuerdo)

2)Tu variable local obtiene una direccion dentro del stack. Imaginate q esta direccion es 0x45D (El numero hexadecimal 45D, equivalente a 1117)

3)Tu funcion retorna la referencia a esta variable, o sea la posicion de memorioa numero 0x45d o 1117

4)La funcion termina de ejecutarse y se libera la pila. Enfatizo que se LIBERA, o sea que cualquier programa puede usarla a su gusto, pero no se elimina!!!! O sea que hasta que algun otro programa o proceso no se le asigne el byte Numero 45d, tu referencia seguira funcionando bien hasta que el sistema operativo asigne esa area a algun otro proceso y entonces todo comenzara a fallar :/


Sobre el operador =, es algo tambien un poco complejo:

El operador *, toma como argumento una variable de tipo racional y devuelve una variable del tipo Racional, hasta ahi vas bien.

este valor devuelto es bastante especial, porque ya saliste de la funcion, asi que la pila es liberada, pero todavia queda un dato que no podemos perder, el valor devuelto que probablemente asignaremos a otra variable. Es especial porque si te das cuenta es un tipo valor que no es parte de tu main (algo en teoria imposible porque solo los punteros y las referencias deberian poder accederse fuera de la pila; pero de esto se encarga el mismo c++ - probablemente volviendolo internamente una referencia - asi q todavia esta bien)

Entonces, viene el operador =, que toma como argumento ese tipo valor tan especial devuelto por el operador *. Normalmente cuando una funcion pide un valor por referencia, pero tu le pasas uno por valor, el c++ se encarga de referenciarla.

El problema es ahora que al parecer el c++ no tiene la capacidad de encargarse de referenciar este tipo, (que ya internamente es una referencia :/) por lo que ese valor devuelto solo podra ser pasado por valor al operador =, causando un error!!


Para arreglar este problema se me ocurren 2 opciones:

1) Crea otra version del operador =, pero pide los argumentos por valor en caso de que la variable no se pueda pasar por referencia como es tu caso:
Código
  1. Racional operator=(Racional r)//notece sin ningun & involucrado...
  2. {
  3.            this->set_racional(r.num,r.den);
  4.            return *this;
  5. }
  6.  

2)Utiliza c# jajajajaj


Bueno si no entiendes algode lo q dije (probable porque soy malo explicando) entonces pregunta lo q no entiendas.

Si quieres averiguar por tu cuenta como funcionan las referencias y las pilas de llamada a funcion, cheka estos links del curso de c++ mas copleto q he visto hasta ahora en la web:

http://www.zator.com/Cpp/E4_2_3.htm
http://www.zator.com/Cpp/E1_3_2.htm



Bye