Foros - Stratos

Programadores => General Programadores => Mensaje iniciado por: Pogacha en 17 de Noviembre de 2005, 12:45:16 AM

Título: Cosa De C++
Publicado por: Pogacha en 17 de Noviembre de 2005, 12:45:16 AM
 Seguid el ejemplo:
class TCosa
{
   TObjetoInterno *OI;

public:

  TCosa(const TObjetoInterno *o = NULL);
  ~TCosa();

  TCosa  operator+(const TCosa &c) const;

  TObjetoInterno *Tomar_ObjetoInterno() const;
};


TObjetoInterno *TCosa::Tomar_ObjetoInterno() const
{
  return OI;
}


TCosa::TCosa(const TObjetoInterno *o)
{
  OI = o;  // es un mal diseño, pero supongamos para que valga el ejemplo
}

TCosa::~TCosa()
{
 if(OI)  delete OI;
}

TCosa TCosa::operator+(const TCosa &c) const
{
  TObjetoInterno *NO = new TObjetoInterno;

  NO->FuncionSuma(OI, c.OI);

  return TCosa(NO);  // Esto es lo que no anda :( , me destruye el objeto antes de pasarlo
}


void main(void)
{
  TCosa a(new TObjetoInterno);
  TCosa b(new TObjetoInterno);
  TCosa c;

  c=a+b;             // esto es lo que no me funciona ...
  c->Tomar_ObjetoInterno()->FuncionHola();    // me termina dando error de proteccion de memoria

}


Como hago para que esto funcione ?
O sea devolver un objeto en una función y que no lo destruya antes?
Nesesito esta funcionalidad ...

Saludos.
Título: Cosa De C++
Publicado por: ProD en 17 de Noviembre de 2005, 01:10:12 AM
 Buenas, ¿Has probado a tener un constructor copia?, quizás te interesaría también tener un
operador de asignación. Saludos
Título: Cosa De C++
Publicado por: zupervaca en 17 de Noviembre de 2005, 10:26:09 AM
 
Citarreturn TCosa(NO);  // Esto es lo que no anda :( , me destruye el objeto antes de pasarlo
el objeto NO no te lo puede destruir ya que lo has creado con new y el objeto TCosa lo esta devolviendo y el lenguaje no lo puede destruir con lo que el fallo no puede estar ahi

por ejemplo yo tengo esto en mi clase vector3
  __forceinline Vector3 Vector3::operator+ ( Vector3 &v )
  {
   return Vector3( x+v.x, y+v.y, z+v.z );
  }
Título: Cosa De C++
Publicado por: CoLSoN2 en 17 de Noviembre de 2005, 11:07:35 AM
 Normal que te pete.

Lo que ocurre es,

En operator+:
- Se crea un objeto dinámico "NO". Para que se borre deberías hacerlo manualmente usando delete.
- Luego creas un objeto estático en el return, y asignas "NO" a él. Este objeto sí será borrado después de _copiarse_ a la variable "c" (en la línea c = a+b;). Al copiarse, el TObjetoInterno* "NO" se comparte entre ambos, porque se igualan los valores de esa variable, que es un puntero.
- Al borrarse la variable estática que se creó en el return, se libera la memoria de "NO" (en ~TCosa()), por lo que el TObjetoInterno* de la variable "c" deja de apuntar a un bloque de memoria válido.

Solución

Sobrecarga el operador de asignación para TCosa y "clona" el miembro "OI" de la clase. Algo como:


TCosa& TCosa::operator=(const TCosa& obj)
{
this.IO = new TObjetoInterno;

// igualar this.IO a obj.IO, aunque lo suyo sería usar un constructor copia
this.IO->miembro = obj->IO->miembro;

return *this;

}


Normalmente, si una clase tiene miembros que son objetos dinámicos (reservas su memoria usando new) querrás sobrecargar el operador de asignación, para que al igualar un objeto de esa clase a otro este objeto no se comparta (si lo cambias o borras en uno de sus padres, también se altera en el otro), sino que se tengan instancias iguales pero independientes.
Título: Cosa De C++
Publicado por: zupervaca en 17 de Noviembre de 2005, 11:19:21 AM
 
CitarOI = o;  // es un mal diseño, pero supongamos para que valga el ejemplo
se supone que el operador = lo tiene como indicas

editado: a pues no, por que tendria que poner el *
Título: Cosa De C++
Publicado por: CoLSoN2 en 17 de Noviembre de 2005, 11:32:07 AM
 Si con OI = o lo que realmente está haciendo es clonar el objeto (crear una nueva instancia y copiar los datos del otro), entonces valdría con cambiar
TCosa c;
c = a+b;

por
TCosa c((a+b).OI);
Título: Cosa De C++
Publicado por: zupervaca en 17 de Noviembre de 2005, 12:32:01 PM
 nos viene ni que pintado este post para otro tema un poco off-topic y es sobre las optimizaciones del compilador, por ejemplo, si en vez de hace esto:

TCosa c;
c=a+b;

hacemos esto

TCosa c=a+b;

¿el objeto creado en el "return TCosa(NO);" se aprovecha o se crea c y otro mas y luego se llama al operador = ? yo creo que en principio optimizaria haciendo que c sea TCosa(NO), pero tampoco lo he mirado nunca, ¿que pensais? ¿o llama al operador = por si se hacen mas cosas?

editado: partiendo de que el operador = de la clase sea el de por defecto sin redifinir
Título: Cosa De C++
Publicado por: CoLSoN2 en 17 de Noviembre de 2005, 12:49:14 PM
 Yo diría que en ningún caso c se "convierte" en el objeto TCosa(NO), siempre se crea y se destruye un objeto estático temporal.
Título: Cosa De C++
Publicado por: zupervaca en 17 de Noviembre de 2005, 12:52:24 PM
 ya, en este codigo es asi, pero si el operador = no estuviera redefinido y estuviera el de por defecto del compilador ¿que ocurriria, optimiza o lo hace como si hubieramos redifinido el operador =?
Título: Cosa De C++
Publicado por: ethernet en 17 de Noviembre de 2005, 03:26:12 PM
 A mi el código no me compila.

Bastaría con poner :


TCosa c=a+b;


y todo funcionaría a la perfección y además es lo más óptimo. En tu caso pasa lo que dice Colson. Recomiendo mirar effective c++ para cosas de ese tipo, hay ejemplos de casi todo eso.

Título: Cosa De C++
Publicado por: CoLSoN2 en 17 de Noviembre de 2005, 03:38:02 PM
Cita de: "ethernet"A mi el código no me compila.

Bastaría con poner :


TCosa c=a+b;


y todo funcionaría a la perfección y además es lo más óptimo. En tu caso pasa lo que dice Colson.
Si pasa lo que digo yo, ¿por qué no pasa lo mismo en este caso?
Título: Cosa De C++
Publicado por: zupervaca en 17 de Noviembre de 2005, 03:44:24 PM
 entonces si de esta manera funciona "TCosa c=a+b;" comprobamos de que el compilador si optimizaria y no llama al operador = ya que el return TCosa(NO) se convierte en c y el objeto NO no es destruido ya que el objeto devuelto por la funcion no es destruido y no se llama al destructor
Título: Cosa De C++
Publicado por: ethernet en 17 de Noviembre de 2005, 03:56:16 PM
Cita de: "CoLSoN2"Si pasa lo que digo yo, ¿por qué no pasa lo mismo en este caso?
Pues porque en este caso se contruye el objeto una sola vez.  
Título: Cosa De C++
Publicado por: Pogacha en 17 de Noviembre de 2005, 04:28:59 PM
 
Cita de: "zupervaca"por ejemplo yo tengo esto en mi clase vector3
  __forceinline Vector3 Vector3::operator+ ( Vector3 &v )
  {
   return Vector3( x+v.x, y+v.y, z+v.z );
  }
Es claro, eso me andaba al galope, tenia años usandolo, pero cuando quize hacer una clase auxiliar para manejo de texto terminé con este problema ...

El operador copia seria "TCosa& TCosa::operator=(const TCosa& obj);"?

Gracias a todos

Edit :

Recien estoy callendo:

Hasta a+b tengo todo bien, pero cuando paso por el = al no tener un operador copia, el compilador hace una copia de memoria (que seria la copia por defecto) del objeto a+b al c, luego destruye el a+b por que se descarta y ahí pierdo el ObjetoInterno de c ...
OK !!!!
(ole)  (ole)  (ole)
Que bueno que lo entendí !!!!
Estoy re contento, en realidad este problema me venia persiguiendo desde hace años y recién ahora logro agarrarlo ... !!!

Saludos y gracias nuevamente

Edit2:

Para que no digan que estoy loco, releí de nuevo y esto me lo decía colson claramente, aun que no le entendí en la primera lectura ...
CitarEn operator+:
- Se crea un objeto dinámico "NO". Para que se borre deberías hacerlo manualmente usando delete.
- Luego creas un objeto estático en el return, y asignas "NO" a él. Este objeto sí será borrado después de _copiarse_ a la variable "c" (en la línea c = a+b;). Al copiarse, el TObjetoInterno* "NO" se comparte entre ambos, porque se igualan los valores de esa variable, que es un puntero.
- Al borrarse la variable estática que se creó en el return, se libera la memoria de "NO" (en ~TCosa()), por lo que el TObjetoInterno* de la variable "c" deja de apuntar a un bloque de memoria válido.

Saludos y gracias por triplicado
Título: Cosa De C++
Publicado por: Yoshi.css en 17 de Noviembre de 2005, 07:53:38 PM
 
CitarHasta a+b tengo todo bien, pero cuando paso por el = al no tener un operador copia, el compilador hace una copia de memoria (que seria la copia por defecto) del objeto a+b al c, luego destruye el a+b por que se descarta y ahí pierdo el ObjetoInterno de c ...
OK !!!!
Y no solo eso. Si realizas la asignación (=) entre dos objetos, y no tienes definido el constructor de copia, el compilador realiza una copia de un objeto en otro bit a bit. El problema surge cuando trabajas con punteros dentro de la clase, y es que ambos objetos estarían accediendo a la mísma dirección de memoria, lo que supone un problema grave y no deseado.